【你不一定知晓的】C#取消异步操作
【你不一定知晓的】C#取消异步操作
在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务)。
早期

private void BackgroundLongRunningTask(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender; for (int i = 1; i <= 10000; 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(() =>
{
decimal result = 0; // Loop for a defined number of iterations
for (int i = 0; i < loop; i++)
{
// Do something that takes times like a Thread.Sleep in .NET Core 2.
Thread.Sleep(10);
result += i;
} return result;
});
}
// 这里我们使用Thread.Sleep 模仿长时间运行的操作

简单异步调用代码:

public static async Task ExecuteTaskAsync()
{
Console.WriteLine(nameof(ExecuteTaskAsync));
Console.WriteLine("Result {0}", await LongRunningOperation(100));
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(() =>
{
decimal result = 0; // Loop for a defined number of iterations
for (int i = 0; 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(10);
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
{
var result = await LongRunningCancellableOperation(500, 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
{
var longRunningTask = LongRunningCancellableOperation(500, 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
var longRunningTask = LongRunningOperationWithCancellationTokenAsync(100, 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;
}
}

总结:
【你不一定知晓的】C#取消异步操作的更多相关文章
- 【.NET异步编程系列3】取消异步操作
在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务). 早期 ...
- 【异步编程】Part3:取消异步操作
在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务). 早期 ...
- 使用BackgroundWorker组件进行异步操作编程
本文介绍了BackgroundWorker组件的功能及在基于事件的异步操作编程中的应用,并对组件的实现原理进行简述.在应用程序中,可能会遇到一些执行耗时的功能操作,比如数据下载.复杂计算及数据库事务等 ...
- [Web] 取消Promise
转载自 为Promise插上可取消的翅膀 const makeCancelable = (promise) => { let hasCanceled_ = false; const wrappe ...
- 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 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- [C#] 走进异步编程的世界 - 剖析异步方法(上)
走进异步编程的世界 - 剖析异步方法(上) 序 这是上篇<走进异步编程的世界 - 开始接触 async/await 异步编程>(入门)的第二章内容,主要是与大家共同深入探讨下异步方法. 本 ...
- Future和Promise
Future用于获取异步操作的结果,而Promise则比较抽象,无法直接猜测出其功能. Future Future最早来源于JDK的java.util.concurrent.Future,它用于代表异 ...
- Event-based Asynchronous Pattern Overview基于事件的异步模式概览
https://msdn.microsoft.com/zh-cn/library/wewwczdw(v=vs.110).aspx Applications that perform many task ...
随机推荐
- xilink 烧写flash
no 右键
- 范进中Nature——儒林外史新义
范进中Nature——儒林外史新义 范进发了文章回办公室,实验室一块儿搬砖的挂名作者俱各欢喜.正待烧锅煮方便面,只见他老板胡副教授,手里拿着一包外卖和一瓶红星二锅头,走了进来.范进向他作揖,坐下.胡副 ...
- spark组件笔记
SparkContext 中最重要的3个组建: 1 TaskScheduler (包含两个内容,TaskSchedulerImpl和SparkDeploySchedulerBackend)-用于向Ma ...
- 探究Java中的锁
一.锁的作用和比较 1.Lock接口及其类图 Lock接口:是Java提供的用来控制多个线程访问共享资源的方式. ReentrantLock:Lock的实现类,提供了可重入的加锁语义 ReadWrit ...
- Oracle不连续的值,如何实现查找上一条、下一条
1. 遇到的问题 已知一个题库,希望实现当前页切换上一题,下一题的需求. 查看得知,数据库中用于查询的字段(主键)是不连续的.如上图所示:stxh为主键number类型. 2. 实现方式lead ...
- mysql 字段唯一性问题
ALTER TABLE tb ADD unique (name);
- 项目中常用的javascript/jquery操作
1.判断复选框是否被选中? $("#cpuWindow").is(':checked'); 2.设置复选框被选中: $("#cpuWindow").prop(& ...
- 从数据库取出两个同样的字符串用equals比较返回false
1. 从网上搜索原因,大概总结为三点 1.1 取数据的两个数据库编码不一样,需要统一编码 1.2 字符类型不一样,可能一个为nchar一个为varchar 1.3 从数据库取出的数据有空格,需要tri ...
- LinkedList 利用的是尾插法
- flutter stack
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp(home: new MyApp())); } clas ...