【.NET异步编程系列3】取消异步操作
在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务)。
早期
private void BackgroundLongRunningTask(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
; i <= ; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
// Do something
}
}
已经不再推荐这种方式来完成异步和长时间运行的操作,但是大部分概念在现在依旧可以使用。
Task横空出世
/// <summary>
/// Compute a value for a long time.
/// </summary>
/// <returns>The value computed.</returns>
/// <param name="loop">Number of iterations to do.</param>
private static Task<decimal> LongRunningOperation(int loop)
{
// Start a task and return it
return Task.Run(() =>
{
;
// Loop for a defined number of iterations
; i < loop; i++)
{
// Do something that takes times like a Thread.Sleep in .NET Core 2.
Thread.Sleep();
result += i;
}
return result;
});
}
// 这里我们使用Thread.Sleep 模仿长时间运行的操作
简单异步调用代码:
public static async Task ExecuteTaskAsync()
{
Console.WriteLine(nameof(ExecuteTaskAsync));
Console.WriteLine());
Console.WriteLine("Press enter to continue");
Console.ReadLine();
}
敲黑板: C#取消异步操作分为

① 让代码可取消(Cancellable)
/// <summary>
/// Compute a value for a long time.
/// </summary>
/// <returns>The value computed.</returns>
/// <param name="loop">Number of iterations to do.</param>
/// <param name="cancellationToken">The cancellation token.</param>
private static Task<decimal> LongRunningCancellableOperation(int loop, CancellationToken cancellationToken)
{
Task<decimal> task = null;
// Start a task and return it
task = Task.Run(() =>
{
;
// Loop for a defined number of iterations
; i < loop; i++)
{
// Check if a cancellation is requested, if yes,
// throw a TaskCanceledException.
if (cancellationToken.IsCancellationRequested)
throw new TaskCanceledException(task);
// Do something that takes times like a Thread.Sleep in .NET Core 2.
Thread.Sleep();
result += i;
}
return result;
});
return task;
}
② 触发取消命令
// 以下代码 利用 CancellationSource默认构造函数 完成超时取消
public static async Task ExecuteTaskWithTimeoutAsync(TimeSpan timeSpan)
{
Console.WriteLine(nameof(ExecuteTaskWithTimeoutAsync));
using (var cancellationTokenSource = new CancellationTokenSource(timeSpan))
{
try
{
, cancellationTokenSource.Token);
Console.WriteLine("Result {0}", result);
}
catch (TaskCanceledException)
{
Console.WriteLine("Task was cancelled");
}
}
Console.WriteLine("Press enter to continue");
Console.ReadLine();
}
------------------------------------------------------------------------------------------------------------
附①: 高阶操作,完成手动取消:
public static async Task ExecuteManuallyCancellableTaskAsync()
{
Console.WriteLine(nameof(ExecuteManuallyCancellableTaskAsync));
using (var cancellationTokenSource = new CancellationTokenSource())
{
// Creating a task to listen to keyboard key press
var keyBoardTask = Task.Run(() =>
{
Console.WriteLine("Press enter to cancel");
Console.ReadKey();
// Cancel the task
cancellationTokenSource.Cancel();
});
try
{
, cancellationTokenSource.Token);
var result = await longRunningTask;
Console.WriteLine("Result {0}", result);
Console.WriteLine("Press enter to continue");
}
catch (TaskCanceledException)
{
Console.WriteLine("Task was cancelled");
}
await keyBoardTask;
}
}// 以上是一个控制台程序,异步接收控制台输入,发出取消命令。
附②:高阶操作,取消 non-Cancellable任务 :
- 利用TaskCompletionSource 注册异步可取消任务
- 等待待non-cancellable 操作和以上建立的 异步取消操作
private static async Task<decimal> LongRunningOperationWithCancellationTokenAsync(int loop, CancellationToken cancellationToken)
{
// We create a TaskCompletionSource of decimal
var taskCompletionSource = new TaskCompletionSource<decimal>();
// Registering a lambda into the cancellationToken
cancellationToken.Register(() =>
{
// We received a cancellation message, cancel the TaskCompletionSource.Task
taskCompletionSource.TrySetCanceled();
});
var task = LongRunningOperation(loop);
// Wait for the first task to finish among the two
var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);
return await completedTask;
}
像上面代码一样执行取消命令 :
public static async Task CancelANonCancellableTaskAsync()
{
Console.WriteLine(nameof(CancelANonCancellableTaskAsync));
using (var cancellationTokenSource = new CancellationTokenSource())
{
// Listening to key press to cancel
var keyBoardTask = Task.Run(() =>
{
Console.WriteLine("Press enter to cancel");
Console.ReadKey();
// Sending the cancellation message
cancellationTokenSource.Cancel();
});
try
{
// Running the long running task
, cancellationTokenSource.Token);
var result = await longRunningTask;
Console.WriteLine("Result {0}", result);
Console.WriteLine("Press enter to continue");
}
catch (TaskCanceledException)
{
Console.WriteLine("Task was cancelled");
}
await keyBoardTask;
}
}
总结:
感谢您的认真阅读,如有问题请大胆斧正,如果您觉得本文对你有用,不妨右下角点个
或加关注。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置注明本文的作者及原文链接,否则保留追究法律责任的权利。
【.NET异步编程系列3】取消异步操作的更多相关文章
- 【异步编程】Part3:取消异步操作
在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务). 早期 ...
- 【.NET异步编程系列1】:await&async语法糖让异步编程如鱼得水
前导 Asynchronous programming Model(APM)异步编程模型以BeginMethod(...) 和 EndMethod(...)结对出现. IAsyncResult Beg ...
- 异步编程系列第02章 你有什么理由使用Async异步编程
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- 异步编程系列第04章 编写Async方法
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- 异步编程系列第05章 Await究竟做了什么?
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- 异步编程系列06章 以Task为基础的异步模式(TAP)
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- 异步编程系列第01章 Async异步编程简介
p { display: block; margin: 3px 0 0 0; } --> 2016.10.11补充 三个月过去了,回头来看,我不得不承认这是一系列失败的翻译.过段时间,我将重新翻 ...
- 【.NET异步编程系列2】掌控SynchronizationContext避免deadlock
引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式. 相信很多开发者都看到如下异步编程实践原 ...
- C#与C++的发展历程第三 - C#5.0异步编程巅峰
系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...
随机推荐
- 使用Swashbuckle构建RESTful风格文档
本次和大家分享的是Swagger to WebApi的nuget包Swashbuckle:因为项目需要统一api文档的风格,并要支持多种开发语言(C#,java,python),所以首先想到的是swa ...
- 深入理解javascript 匿名函数和闭包
代码如下: (function(){ //这里忽略jQuery所有实现 })(); (function(){ //这里忽略jQuery所有实现 })(); 半年前初次接触jQuery的时候,我也像其 ...
- Beta 冲刺day3
1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:昨天主要是对第三方与企业复杂的逻辑关系进行分析和优化,以及进行部分模块的功能测试和代码测试. 今天解决的进度:根据前天得到的需求问题进行 ...
- Cython入门Demo(Linux)
众所周知,Python语言是非常简单易用的,但是python程序在运行速度上还是有一些缺陷.于是,Cython就应运而生了,Cython作为Python的C扩展,保留了Python的语法特点,集成C语 ...
- C# 发展史
C# 发展史 Intro 本文主要总结介绍C# 每个版本带来的不同的语言特性. C#,读作C Sharp,是微软推出的一种基于.NET平台的.面向对象的高级编程语言.是微软公司在2000年发布的一种新 ...
- VS2010+OpenCV3.4.1+zbar 64位
1. OpenCV3.4.1和zbar文件夹放到指定的路径下,我把它们放在了"D:\二维码\环境"中. zbar:链接:https://pan.baidu.com/s/11eCDV ...
- PAT1061:Dating
1061. Dating (20) 时间限制 150 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Sherlock Holme ...
- java对象深复制、浅复制(深拷贝、浅拷贝)的理解
先看一个例子 User user1 = new User(); user1.setId("111"); Map<String, User> map1 = new Has ...
- mysql 从一个表中查数据,插入另一个表
其实很简单,只是为了忘记,做个记录,用的时候方便. 不管是在网站开发还是在应用程序开发中,我们经常会碰到需要将MySQL或MS SQLServer某个表的数据批量导入到另一个表的情况,甚至有时还需要指 ...
- CentOS6.5系统挂载NTFS分区的硬盘
下载rpmforge,下载对应的版本,就是对应CentOS版本,还有32位与64位也要对应上.rpmforge拥有4000多种CentOS的软件包,被CentOS社区认为是最安全也是最稳定的一个软件仓 ...