取消任务
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: ... ...
只要执行代码时用到了超时,就该使用 CancellationTokenSource
和 CancelAfter
(或者用构造函数)。虽然还有其他途径可实现这个功能,但是使用现有的取消体系是最简单也是最高效的。
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");
}
}
注意: 为了避免内存和资源的泄漏,一旦不再需要使用回调函数了,就要释放这个回调函数注册。
相关文章推荐
- 基于ContentObserver来动态取消或添加屏幕超时任务
- System.Threading.Tasks.TaskCanceledException: 已取消一个任务
- linux中创建定时任务与取消
- 通过Future来取消正在执行的任务
- mysql定时任务,超过7天未付款,删除订单取消交易
- 取消框架 取消并行或任务的超长时间执行 CancellationToken
- .Net 4.5中通过CancellationTokenSource实现对超时任务的取消
- 部署OVF模板失败,提示用户取消任务
- 任务的取消与关闭(java并发编程实践读书笔记六)
- Java 并发编程之任务取消(五)
- 并发编程 07—— 任务取消
- Android线程池中的任务取消
- 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
- 任务执行与取消
- 重启打印机(打印机任务无法取消时)
- java多线程6.任务取消与关闭
- Java并发编程(五) 任务的取消
- Java 并发编程之任务取消 (三)
- 并行编程中的取消任务、共享状态,等等
- 使用Future的cancel()方法来取消已经提交给执行者的任务