志在指尖
用双手敲打未来

C# 线程知识–使用Task执行异步操作

Console.WriteLine(“主线程执行其他处置”);
15://主线程挂起1000毫秒,等候任务的完成。
16:Thread.Sleep(1000);
17:}
任务调度结果:image
2.等候任务的完成并获取返回值
运用任务执行异步操作时,最主要的是要后的任务完成时的返回值。在任务类中有一个实例办法Wait(有许多重载版本)他能等候任务的完成,我们也能够经过Task类的派生类Task创立一个异步任务,并指定任务完成时返回值的类型,这样能够经过Task的实例对象获取到任务完成后的返回值。创立一个异步任务并执行0到100求和操作返回最后的计算结果,示例代码:c#语言的特点是什么
1:staticvoidTaskWait(){
2://创立任务
3:Task<int>task=newTask<int>(()=>
4:{
5:intsum=0;
6:Console.WriteLine(“运用Task执行异步操作.”);
7:for(inti=0;i<100;i++)
8:{
9:sum+=i;
10:}
11:returnsum;
12:});
13://启动任务,并布置到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
14:task.Start();
15:
16:Console.WriteLine(“主线程执行其他处置”);
17://等候任务的完成执行过程。
18:task.Wait();
19://取得任务的执行结果
20:Console.WriteLine(“任务执行结果:{0}”,task.Result.ToString());
21:}
执行结果:image
Task类还有一些静态办法,WaitAll用于等候提供的一切System.Threading.Tasks.Task对象完成执行过程和Wait用于等候提供的任一个System.Threading.Tasks.Task对象完成执行过程,这两个办法都有一些重载版本。
//等候一切任务完成
publicstaticvoidWaitAll(paramsTask[]tasks);
//等候恣意一个任务完成
publicstaticintWaitAny(paramsTask[]tasks);
3.运用ContinueWith办法在任务完成时启动一个新任务
在运用可以Task类的Wait办法等候一个任务时或派生类的Result属性取得任务执行结果都有可能阻塞线程,为理解决这个问题能够运用ContinueWith办法,他能在一个任务完成时自动启动一个新的任务来处置执行结果。
示例代码:
1:staticvoidTaskContinueWith()
2:{
3://创立一个任务
4:Task<int>task=newTask<int>(()=>
5:{
6:intsum=0;
7:Console.WriteLine(“运用Task执行异步操作.”);
8:for(inti=0;i<100;i++)
9:{
10:sum+=i;
11:}
12:returnsum;
13:});
14://启动任务,并布置到当前任务队列线程中执行任务(System.Threading.Tasks.TaskScheduler)
15:task.Start();
16:Console.WriteLine(“主线程执行其他处置”);
17://任务完成时执行处置。
18:Taskcwt=task.ContinueWith(t=>{
19:Console.WriteLine(“任务完成后的执行结果:{0}”,t.Result.ToString());
20:});
21:Thread.Sleep(1000);
22:}
执行结果:image
上述示例中任务不是等候完成来显现执行结果,而是运用ContinueWith办法,它可以晓得任务在什么时分完成并启动一个新的任务来执行任务完成后的处置。ContinueWith办法具有一些重载版本,这些重载版本允许指定持续任务需求运用的数据、持续任务的工作方式(System.Threading.Tasks.TaskContinuationOptions的枚举值按位OR运转的结果)等。
4.创立父子任务和任务工厂的运用
经过Task类创立的任务是顶级任务,能够经过运用TaskCreationOptions.AttachedToParent标识把这些任务与创立他的任务相关联,一切子任务全部完成以后父任务才会完毕操作。示例如下:
1:staticvoidParentChildTask(){
2:Task<string[]>parent=newTask<string[]>(state=>{
3:Console.WriteLine(state);
4:string[]result=newstring[2];
5://创立并启动子任务
6:newTask(()=>{result[0]=”我是子任务1。”;},TaskCreationOptions.AttachedToParent).Start();
7:newTask(()=>{result[1]=”我是子任务2。”;},TaskCreationOptions.AttachedToParent).Start();
8:returnresult;
9:},”我是父任务,并在我的处置过程中创立多个子任务,一切子任务完成以后我才会完毕执行。”);
10://任务处置完成后执行的操作
11:parent.ContinueWith(t=>{
12:Array.ForEach(t.Result,r=>Console.WriteLine(r));
13:});
14://启动父任务
15:parent.Start();
16:Console.Read();
17:}
执行结果:image
假如需求创立一组具有相同状态的任务时,能够运用TaskFactory类或TaskFactory类。这两个类创立一组任务时能够指定任务的CancellationToken、TaskCreationOptions、TaskContinuationOptions和TaskScheduler默许值。示例代码:
1:staticvoidTaskFactoryApply()
2:{
3:Taskparent=newTask(()=>
4:{
5:CancellationTokenSourcects=newCancellationTokenSource(5000);
6://创立任务工厂
7:TaskFactorytf=newTaskFactory(cts.Token,TaskCreationOptions.AttachedToParent,TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
8://添加一组具有相同状态的子任务
9:Task[]task=newTask[]{
10:tf.StartNew(()=>{Console.WriteLine(“我是任务工厂里的第一个任务。”);}),
11:tf.StartNew(()=>{Console.WriteLine(“我是任务工厂里的第二个任务。”);}),
12:tf.StartNew(()=>{Console.WriteLine(“我是任务工厂里的第三个任务。”);})
13:};
14:});
15:parent.Start();
16:Console.Read();
17:}
执行结果:image
5.任务内部完成和任务调度
任务内部有一组构成任务状态的属性,标识任务的独一Id、表示任务的执行状态(TaskStatus)、任务创立时提供的回调函数的援用和传送给回调函数的数据对象AsyncState、对任务创立时的任务调度对象(TaskScheduler)的援用、对父任务的援用以及对执行上下文的援用和ManualResetEventSlim对象的援用。Task类和Task类都完成了规范的释放资源的接口,允许在任务完成处置的时分运用Dispose办法释放资源(关闭ManualResetEventSlim对象实例)。能够运用Task类的CurrentId属性取得正在执行的任务的Id,假如没有任务在执行CurrentId返回值为null,CurrentId是一个int?可空类型的属性。任务执行的生命周期经过TaskStatus类型的一个值来表示,TaskStatus所包含的值:
publicenumTaskStatus
{
Created=0,
WaitingForActivation=1,
WaitingToRun=2,
Running=3,
WaitingForChildrenToComplete=4,
RanToCompletion=5,
Canceled=6,
Faulted=7,
}
我们能够经过Task类的Exception属性取得任务在执行过程中的一切异常
,Exception是一个AggregateException类型的属性。Task类提供了IsCanceled、IsCompleted、IsFaulted属性来取得任务的完成状态。经过ContinueWith、ContinueWhenAll、ContinueWhenAny和FromAsync创立的后续任务都处于WaitingForActivation状态,这个状态的任务会在父任务完成后自动执行。
在任务内部由TaskScheduler类调度任务的执行,该类是一个笼统类,FCL中从他派生了两个派生类:ThreadPoolTaskScheduler线程池任务调度器和SynchronizationContextTaskScheduler同步上下文任务调度器。一切任务默许都是采用ThreadPoolTaskScheduler调度任务,他是采用线程池来执行任务,能够经过TaskScheduler类的静态属性Default取得对默许任务调度器的援用。SynchronizationContextTaskScheduler任务调度器可以用在Windowform、WPF等应用程序,他的任务调度是采用的GUI线程,所以他能同步更新UI组件,能够经过TaskScheduler类的静态办法FromCurrentSynchronizationContext取得对一个同步上下文任务调度起的援用。
任务调度示例:
1:privatevoidbutton1_Click(objectsender,EventArgse)
2:{
3://取得同步上下文任务调度器
4:TaskSchedulerm_syncContextTaskScheduler=TaskScheduler.FromCurrentSynchronizationContext();
5:
6://创立任务,并采用默许任务调度器(线程池任务调度器)执行任务
7:Task<int>task=newTask<int>(()=>
8:{
9://执行复杂的计算任务。
10:Thread.Sleep(2000);
11:intsum=0;
12:for(inti=0;i<100;i++)
13:{
14:sum+=i;
15:}
16:returnsum;
17:});
18:varcts=newCancellationTokenSource();
19://任务完成时启动一个后续任务,并采用同步上下文任务调度器调度任务更新UI组件。
20:task.ContinueWith(t=>{this.label1.Text=”采用SynchronizationContextTaskScheduler任务调度器更新UI。\r\n计算结果是:”+task.Result.ToString();},
21:cts.Token,TaskContinuationOptions.AttachedToParent,m_syncContextTaskScheduler);
22:task.Start();
23:}
执行结果:image
本文简单的引见了运用Task类来执行异步操作以及任务的内部完成与任务调度。在执行复杂异步操作时,能够采用任务来执行,他能更好的晓得异步操作在何时完成以及返回异步操作的执行结果。

未经允许不得转载:IT技术网站 » C# 线程知识–使用Task执行异步操作
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载