用3种方式来实现异步取消Task后向当前SynchronizationContext执行操作
2013-01-19 23:04
501 查看
.NET TPL拥有非常大的灵活性,你会发现同一个操作会有许多不同的实现方式。正如标题所讲,我们来看这样一个简答的操作:取消Task的执行,然后在当前SynchronizationContext中执行代码。当然一切操作都必须是异步的,因此不能使用Task.Wait这样的方法。
我想到的实现方法有三种。
首先是准备工作,先写一个方法用来执行一个可以取消的Task,之后的具体实现代码就直接调用这个方法:
//执行一个可以取消的Task
static Task NewCancellableTask(CancellationToken token)
{
return Task.Run(() =>
{
while (true)
{
System.Threading.Thread.Sleep(1000);
token.ThrowIfCancellationRequested();
}
});
}
接下来看三种具体实现。
目录
方法一:使用await
方法二:使用ContinueWith和TaskScheduler
方法三:使用CancellationToken.Register方法
返回目录
var cts = new CancellationTokenSource();
//执行取消操作
cts.CancelAfter(1000);
try
{
await NewCancellableTask(cts.Token);
}
catch (OperationCanceledException)
{
//收集OperationCanceledException
MessageBox.Show("操作取消");
}
运行几秒钟后,会显示“操作取消”对话框。
返回目录
TaskContinuationOptions.OnlyOnCanceled
来确保只有在Task被取消后,后续操作才会被执行。
由于没有用await,因此SynchronizationContext的执行需要我们自己来做,方法就是使用TaskScheduler.FromCurrentSynchronizationContext方法来返回一个从当前SynchronizationContext创建的TaskScheduler。
Task.ContinueWith有诸多重载,我们使用这一个:
Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationTokencancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler);
最终代码:
var cts = new CancellationTokenSource();
//执行取消操作
cts.CancelAfter(1000);
//ContinueWith
NewCancellableTask(cts.Token).ContinueWith(
t => MessageBox.Show("操作取消"),
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled,
TaskScheduler.FromCurrentSynchronizationContext());
(ContinueWith的Task事实上返回一个Task<MessageBoxResult>)
同样,运行成功。
返回目录
下图:CancellationToken.Register方法的参数:
那么使用这种方法的实现代码:
var cts = new CancellationTokenSource();
//注册操作
cts.Token.Register(() => MessageBox.Show("操作取消"), true);
//执行取消操作
cts.CancelAfter(1000);
//直接执行Task,不需要其他操作。
NewCancellableTask(cts.Token);
这种方法比较少见,不过看起来还不错。
我想到的实现方法有三种。
首先是准备工作,先写一个方法用来执行一个可以取消的Task,之后的具体实现代码就直接调用这个方法:
//执行一个可以取消的Task
static Task NewCancellableTask(CancellationToken token)
{
return Task.Run(() =>
{
while (true)
{
System.Threading.Thread.Sleep(1000);
token.ThrowIfCancellationRequested();
}
});
}
接下来看三种具体实现。
目录
方法一:使用await
方法二:使用ContinueWith和TaskScheduler
方法三:使用CancellationToken.Register方法
返回目录
方法一:使用await
这必须是首选,C# 5.0的await隐藏了许多TPL中的逻辑,以至于可以使异步执行的代码从外表上看起来和同步执行没太大区别。如下代码:var cts = new CancellationTokenSource();
//执行取消操作
cts.CancelAfter(1000);
try
{
await NewCancellableTask(cts.Token);
}
catch (OperationCanceledException)
{
//收集OperationCanceledException
MessageBox.Show("操作取消");
}
运行几秒钟后,会显示“操作取消”对话框。
返回目录
方法二:使用ContinueWith和TaskScheduler
第二种方法我使用Task.ContinueWith,并且使用:TaskContinuationOptions.OnlyOnCanceled
来确保只有在Task被取消后,后续操作才会被执行。
由于没有用await,因此SynchronizationContext的执行需要我们自己来做,方法就是使用TaskScheduler.FromCurrentSynchronizationContext方法来返回一个从当前SynchronizationContext创建的TaskScheduler。
Task.ContinueWith有诸多重载,我们使用这一个:
Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationTokencancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler);
最终代码:
var cts = new CancellationTokenSource();
//执行取消操作
cts.CancelAfter(1000);
//ContinueWith
NewCancellableTask(cts.Token).ContinueWith(
t => MessageBox.Show("操作取消"),
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled,
TaskScheduler.FromCurrentSynchronizationContext());
(ContinueWith的Task事实上返回一个Task<MessageBoxResult>)
同样,运行成功。
返回目录
方法三:使用CancellationToken.Register方法
CancellationToken类型有一个Register方法可以传入一个委托,当CancellationToken被取消后这个委托会被调用。更不可思议的是,它还有一个useSynchronizationContext参数来指定是否回调方法被执行在当前SynchronizationContext上,非常给力。当然Register方法还可以传递一个额外参数,本例不需要使用。下图:CancellationToken.Register方法的参数:
那么使用这种方法的实现代码:
var cts = new CancellationTokenSource();
//注册操作
cts.Token.Register(() => MessageBox.Show("操作取消"), true);
//执行取消操作
cts.CancelAfter(1000);
//直接执行Task,不需要其他操作。
NewCancellableTask(cts.Token);
这种方法比较少见,不过看起来还不错。
相关文章推荐
- 原生javascript实现异步的7种方式
- js异步的实现方式
- Android中实现异步任务机制方式:AsyncTask
- 实现PHP多线程异步请求的3种方法
- Android moveTaskToBack()方法实现手动隐藏当前Activity
- C# 5.0 以Task方式实现EAP
- Android中实现可滑动的Tab的3种方式
- 个人笔记 jq 01 jq的方式实现取消文本框只读
- 异步委托的几种实现方式
- Android学习系列(二)布局管理器之线性布局的3种实现方式
- MVC验证10-到底用哪种方式实现客户端服务端双重异步验证
- 3种方式实现KVO并进行对比
- jSP的3种方式实现radio ,checkBox,select的默认选择值。
- AsyncTask和Handler两种异步方式的实现和区别比较
- Android中通过view方式获取当前Activity的屏幕截图实现方法
- Java进阶学习2-多线程实现的3种方式
- 用户态多线程的3种实现方式
- 3种方式实现Java多线程
- C# 中实现快捷键的3种不同的方式
- css实现正方形div的3种方式