C#中 Task 结合 CancellationTokenSource的妙用

在.NET中,CancellationTokenSourceCancellationTokenTask是处理异步操作和取消任务的重要工具。本文将通过一些简单的例子,帮助你理解它们的用法和协作方式。


CancellationTokenSource

CancellationTokenSource 是一个取消操作的触发器。它用于生成和管理CancellationToken,并控制取消信号的发出。

常用属性和方法
  • Token: 返回一个与此源关联的CancellationToken
  • Cancel(): 触发取消操作。
  • CancelAfter(milliseconds): 指定时间后触发取消操作。
  • Dispose(): 释放资源。
示例
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task.Run(() => {
    for (int i = 0; i < 10; i++)
    {
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Task canceled");
            break;
        }
        Console.WriteLine($"Task running: {i}");
        Thread.Sleep(500);
    }
});

Thread.Sleep(2000);
cts.Cancel();
CancellationToken

CancellationToken 是用于传播取消请求的轻量级结构。它由CancellationTokenSource生成。

常用属性和方法
  • IsCancellationRequested: 是否收到取消请求。
  • ThrowIfCancellationRequested(): 如果已请求取消,抛出OperationCanceledException
  • Register(Action): 注册一个取消时触发的回调。
示例
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task.Run(() => {
    token.Register(() => Console.WriteLine("Cancellation registered"));

    try
    {
        for (int i = 0; i < 10; i++)
        {
            token.ThrowIfCancellationRequested();
            Console.WriteLine($"Task running: {i}");
            Thread.Sleep(500);
        }
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Task was canceled");
    }
});

Thread.Sleep(2000);
cts.Cancel();
Task与CancellationToken

Task 是.NET中的异步操作单元。结合CancellationToken可以在任务运行时取消它。

示例:取消任务
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task task = Task.Run(() => {
    for (int i = 0; i < 10; i++)
    {
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Task canceled");
            break;
        }
        Console.WriteLine($"Task running: {i}");
        Thread.Sleep(500);
    }
}, token);

Thread.Sleep(2000);
cts.Cancel();

try
{
    task.Wait();
}
catch (AggregateException ex)
{
    foreach (var inner in ex.InnerExceptions)
    {
        if (inner is TaskCanceledException)
        {
            Console.WriteLine("Task cancellation exception caught");
        }
    }
}
示例:带超时的任务
var cts = new CancellationTokenSource(3000); // 3秒后自动取消
CancellationToken token = cts.Token;

Task.Run(() => {
    try
    {
        for (int i = 0; i < 10; i++)
        {
            token.ThrowIfCancellationRequested();
            Console.WriteLine($"Task running: {i}");
            Thread.Sleep(1000);
        }
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Task canceled due to timeout");
    }
});
小结
  1. 使用CancellationTokenSource来控制取消。
  2. 通过CancellationToken将取消信号传递给任务或方法。
  3. 任务中可以通过ThrowIfCancellationRequested或检查IsCancellationRequested响应取消请求。
  4. 合理使用Register可以处理取消时的回调逻辑。

通过灵活运用这些工具,你可以编写更高效、可控的异步程序。


原创作者: chenyishi 转载于: https://www.cnblogs.com/chenyishi/p/18620273
### C#CancellationTokenSource 的使用教程 #### 创建和初始化 CancellationTokenSource 对象 为了能够取消任务,首先需要创建 `CancellationTokenSource` 实例。可以通过指定超时时间来自动触发取消操作。 ```csharp // 创建一个带有3秒超时的CancellationTokenSource CancellationTokenSource cts = new CancellationTokenSource(3 * 1000); ``` 此代码片段展示了如何设置具有特定毫秒数作为延迟的时间间隔,在该时间段过后会发出取消请求[^1]。 #### 单个 Task 取消机制 当处理单个异步任务时,可以直接将 token 参数传递给 task 构造函数或 StartNew 方法: ```csharp var task = Task.Run(() => { while (true) { // 定期检查是否有取消请求 cts.Token.ThrowIfCancellationRequested(); Console.WriteLine("Working..."); Thread.Sleep(500); // 模拟工作负载 } }, cts.Token); try { await task; } catch(OperationCanceledException ex) when(cts.IsCancellationRequested){ Console.WriteLine("Task was cancelled."); } finally{ cts.Dispose(); } ``` 上述例子中,如果调用了 `Cancel()` 或者达到了设定的超时期限,则抛出 OperationCancelledException 异常并打印消息 "Task was cancelled." 同时释放资源[^2]. #### 多个 Tasks 联合管理 对于多个并发执行的任务而言,可以利用 `CreateLinkedTokenSource` 来组合不同的 cancellation tokens 成一个新的联合 token source: ```csharp // 建立两个独立的CancellationTokenSources var firstCTS = new CancellationTokenSource(); var secondCTS = new CancellationTokenSource(); // 将它们链接起来形成新的token源 using var linkedTokens = CancellationTokenSource.CreateLinkedTokenSource(firstCTS.Token, secondCTS.Token); // 开启若干子任务... List<Task> tasks = Enumerable.Range(0, 5).Select(_ => Task.Run(async ()=> { try { doWork(linkedTokens.Token); } catch(TaskCanceledException e){ Debug.WriteLine($"A task has been canceled due to {e.Message}"); } }).ToList(); await Task.WhenAll(tasks.ToArray()); if (!linkedTokens.IsCancellationRequested) { // 执行一些清理逻辑 } void doWork(CancellationToken ct) { for(int i = 0 ;i<10;i++) { if(i==7 && !ct.CanBeCanceled){return;} Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Working on iteration #{i}"); await Task.Delay(TimeSpan.FromMilliseconds(ThreadSafeRandom.NextDouble()*10),ct); } } ``` 这里定义了一个辅助方法 `doWork`,它接受一个 cancellationToken 并在其循环体内定期检测是否收到取消信号。一旦任何一个关联的令牌被标记为已请求取消状态(`CanBeCanceled=false`),整个过程就会提前退出.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值