使用Task

使用ThreadPool可以方便的发起异步操作,但却无法知道操作在何时完成,且无法直接获取操作的返回值,为此CLR提供了对线程池的再一次包装,即Task类。Task内部实际上也是使用线程池,只不过封装了一些高级功能。

Task支持直接获取任务执行结果,例如:

1
2
3
4
5
6
7
8
Task<int> t = new Task<int>(n=>Sum(int n),1000);
t.Start();
//执行其它操作
Thread.Sleep(2000);
//显式等待Task完成
//t.Wait();
//在需要结果的时候访问结果
Console.WriteLine(t.Result);

无论是等待还是访问结果,都会阻塞当前线程以等待任务运行完毕。如果此时任务还未被调度给线程池线程执行,则可能会直接分配给当前线程以提高性能。

Task的取消与ThreadPool相似,传递一个CTS即可。不同之处在于Task支持返回结果,因此Task会在取消任务时抛出异常以区别于正常结束任务。为了方便区分,推荐在任务方法中使用CT.ThrowIfCancellationRequested以抛出OperationCanceledException.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CancellationTokenSource cts = new CancellationTokenSource();
Task t = new Task<int>(()=>Sum(1000,cts.Token),cts.Token);
t.Start();
Thread.Sleep(100);
cts.Cancel();
try
{
Console.WriteLine(t.Result);
}
catch (AggregateException ex)
{
//如果是取消产生的异常,则忽略
x.Handle(ex=>ex is OperationCanceledException;
Console.WriteLine("操作取消");
}

Static int Sum(int n, CancellationToken ct)
{
int sum=0;
for(int i =1;i<=n;i++)
{
//检查是否已取消并抛出异常
ct.ThrowIfCancellationRequested();
sum+=i;
}
return sum;
}

延续任务

Task支持在任务完成后继续执行其它任务,并可指定延续任务的执行条件

1
2
Task<int> t = Task.Run(()=>Sum(1000,cts.Token),cts.Token);
t.ContinueWith(task=>Console.WriteLine(task.Result,TaskContinuationOptions);

其中t作为参数被传递到延续任务中

父子任务

可以在一个Task中包含若干个子任务,只有在所有子任务完成后父任务才会被标记为完成状态

1
2
3
4
5
6
7
8
Task<int[]> parent=new Task<int[]>(()=>{
var results=new int[3];
new Task(()=>results[0]=Sum(1000),TaskCreationOptions.AttachedtoParent).Start();
new Task(()=>results[1]=Sum(2000),TaskCreationOptions.AttachedtoParent).Start();
new Task(()=>results[2]=Sum(3000),TaskCreationOptions.AttachedtoParent).Start();
return results;
});
parent.Start();

任务调度器

Task在内部使用TaskScheduler进行任务调度,CLR内部使用了两个派生类,分别是基于线程池的线程池调度器和基于同步上下文的上下文调度器。
线程池调度器是Task的默认调度器,而同步上下文调度器适用于更新GUI的任务,因为.NET禁止从非GUI线程更新界面。

1
2
3
4
5
6
7
8
9
Class MyForm:Form
{
public MyForm
{
Task t=new Task(()=>SomeWork())
t.ContinueWith(task => Text = "任务完成", CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext);
t.Start();
}
}

 评论




载入天数...载入时分秒...  |  总访问量为
Powered by Github and MarkdownPad 2

--------------------------- 别拉了,我是有底线的>_< ---------------------------