C# 实现Task(长时间运行任务)的Start、Pause、Resume、Stop

  • 直接上代码
/// <summary>
/// 长时间工作Task服务
/// </summary>
public class LongRunningTaskService
{
    private CancellationTokenSource _stopCts;

    private readonly SemaphoreSlim pauseSlim = new SemaphoreSlim(0, 1);

    private Task _workTask;

    public void Start()
    {
        _stopCts = new();
        _workTask = Task.Factory.StartNew(async () => await TaskJob(_stopCts.Token), _stopCts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        if (pauseSlim.CurrentCount == 0)
            pauseSlim.Release();
        Console.WriteLine($"Starting Service...");
    }

    public void Pause()
    {
        Console.WriteLine("Pausing Service...");
        pauseSlim.Wait();
    }

    public void Resume()
    {
        Console.WriteLine("Resuming Service...");
        pauseSlim.Release();
    }

    public void Stop()
    {
        Console.WriteLine("Stopping Service...");
        _stopCts?.Cancel();
        _stopCts?.Dispose();
        _stopCts = null;
        _workTask = null;
    }

    private async Task TaskJob(CancellationToken token)
    {
        try
        {
            while (!token.IsCancellationRequested)
            {
                if (pauseSlim.CurrentCount == 0)
                {
                    await pauseSlim.WaitAsync(token);
                    pauseSlim.Release();
                }
                Console.WriteLine("Working...");
                await Process(token);
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Service Stopped");
        }
    }
    /// <summary>
    /// 模拟单个耗时异步任务
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    private async Task Process(CancellationToken token)
    {
        await Task.Delay(1000, token);
    }
}
  • 关键点解释
  • 使用CancellationTokenSource来控制Task任务的取消(停止),将_stopCts作为线程委托启动参数传递(_stopCts调用Cancel方法时,异步任务的委托方法的while轮询将会跳出,从而达到取消任务效果)。
  • 将长时间运行的Task标记为TaskCreationOptions.LongRunning的作用:该Task任务将不是默认从线程池中获取线程,而是单独创建一个独立线程来运行任务。
  • 注意:CancellationTokenSource调用Cancel后,它的CancellationToken传递至的地方,都有可能触发OperationCanceledException或TaskCanceledException,记得捕获这两个异常。
  • 适合异步方法中的信号量很少,这里使用SemaphoreSlim来实现控制Task任务的暂停和继续。通过调用Wait将该信号量的CurrentCount置为0,从而使Task委托进入“等待获取进入权限”状态,实现暂停效果。通过调用Release方法,使Task委托的pauseSlim.WaitAsync获取到“继续运行的权限”(WaitAsync成功后一定要调用Release方法释放锁,防止死锁,同时也将CurrentCount置为1),实现继续效果。
posted @ 2025-06-10 14:44  星渐渐被你吸引  阅读(202)  评论(0)    收藏  举报