您的位置:首页 > 运维架构

取消任务

2020-03-19 20:29 78 查看

https://www.cnblogs.com/BigBrotherStone/archive/2020/02/01/12248808.html


>>返回《C# 并发编程》

  • 1. 取消请求
  • 2. 超时后取消
  • 3. 取消并行
  • 4. 取消响应式代码
  • 5. 与其他取消体系的互操作

CancellationToken.None 是一个等同于默认的特殊值,表示这个方法是永远不会被取消的。

实例代码

static async Task CancelableMethodAsync(CancellationToken token)
{
await Task.Delay(1000, token);
throw new ArgumentException();
}
public static async Task IssueCancelRequestAsync()
{
var cts = new CancellationTokenSource();
var task = CancelableMethodAsync(cts.Token);
// 这里,操作在正常运行。
// 发出取消请求。
cts.Cancel();
//(异步地)等待操作结束。
try
{
await task;
// 如运行到这里,说明在取消请求生效前,操作正常完成 。
}
catch (OperationCanceledException ex)
{
// 如运行到这里,说明操作在完成前被取消。
System.Console.WriteLine(ex.GetType().Name);
}
catch (Exception ex)
{
// 如运行到这里,说明在取消请求生效前,操作出错并结束。
System.Console.WriteLine(ex.GetType().Name);
}
}

输出:

TaskCanceledException

1. 取消请求

public static int CancelableMethod(CancellationToken cancellationToken)
{
for (int i = 0; i != 100000; ++i)
{
// cancellationToken.WaitHandle.WaitOne(1000);
Thread.Sleep(1);
// 这里做一些计算工作。
if (i % 1000 == 0)
cancellationToken.ThrowIfCancellationRequested();
}
return 42;
}

2. 超时后取消

public static async Task IssueTimeoutAsync()
{
Stopwatch sw = Stopwatch.StartNew();
try
{
var cts = new CancellationTokenSource();
var token = cts.Token;
cts.CancelAfter(TimeSpan.FromSeconds(2));
await Task.Delay(TimeSpan.FromSeconds(4), token);
}
finally
{
System.Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
}

输出:

2004ms
Unhandled Exception: ... ...

只要执行代码时用到了超时,就该使用 CancellationTokenSourceCancelAfter (或者用构造函数)。虽然还有其他途径可实现这个功能,但是使用现有的取消体系是最简单也是最高效的。

3. 取消并行

public class Matrix
{
public void Rotate(float degrees) { }
}

//只做展示
public static void RotateMatrices(IEnumerable<Matrix> matrices, float degrees, CancellationToken token)
{
Parallel.ForEach(matrices, new ParallelOptions
{
CancellationToken = token
},
matrix => matrix.Rotate(degrees));
}

4. 取消响应式代码

注入取消请求

  • 某一个层次的代码需要响应取消请求,同时它本身也要向下一层代码发出取消请求(但不会向上传递)。
public static async Task RunGetWithTimeoutAsync()
{
CancellationTokenSource source = new CancellationTokenSource();
await GetWithTimeoutAsync("http://www.baidu.com", source.Token);
}

public static async Task<HttpResponseMessage> GetWithTimeoutAsync(string url, CancellationToken cancellationToken)
{
var client = new HttpClient();
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
cts.CancelAfter(TimeSpan.FromMilliseconds(100));
var combinedToken = cts.Token;
return await client.GetAsync(url, combinedToken);
}
}

输出:

Unhandled Exception: Unhandled exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AggregateException: One or more errors occurred. (A task was canceled.) ---> System.Threading.Tasks.TaskCanceledException ... ...

5. 与其他取消体系的互操作

有一些外部的或以前遗留下来的代码采用了非标准的取消模式。现在要用标准的CancellationToken 来控制这些代码

public static async Task RunPingAsync()
{
var cts = new CancellationTokenSource();
var task = PingAsync("192.168.0.101", cts.Token);
//cts.Cancel();
await task;
}
public static async Task<PingReply> PingAsync(string hostNameOrAddress, CancellationToken cancellationToken)
{
Stopwatch sw = Stopwatch.StartNew();
try
{
var ping = new Ping();
using (cancellationToken.Register(() => ping.SendAsyncCancel()))
{
return await ping.SendPingAsync(hostNameOrAddress);
}
}
finally
{
System.Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
}

注意: 为了避免内存和资源的泄漏,一旦不再需要使用回调函数了,就要释放这个回调函数注册。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gt stopwatch