C#Task循环任务_C#异步编程
(给DotNet加星标,提升.Net技能)
转⾃: yswenli cnblogs/yswenli/p/11987377.html
前⾔
基于Task的异步编程模式(TAP)是Microsoft为.Net平台下使⽤Task进⾏编程所提供的⼀组建议,这种模式提供了可以被await消耗(调⽤)⽅法的APIs,并且当使⽤async关键字编写遵守这种模式的⽅法时,⼿写Task通常很有⽤。通常TAP⽤起来与普通⽅式没什么两样,但是不⽀持ref和out参数。
任务和线程的区别:
1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执⾏。
2、任务跟线程不是⼀对⼀的关系,⽐如开10个任务并不是说会开10个线程,这⼀点任务有点类似线程池,但是任务相⽐线程池有很⼩的开销和精确的控制。
3、Task的优势
ThreadPool相⽐Thread来说具备了很多优势,但是ThreadPool却⼜存在⼀些使⽤上的不⽅便。⽐如:
ThreadPool不⽀持线程的取消、完成、失败通知等交互性操作;
ThreadPool不⽀持线程执⾏的先后次序;
以往,如果开发者要实现上述功能,需要完成很多额外的⼯作,现在,微软提供了⼀个功能更强⼤的概念:Task。Task在线程池的基础上进⾏了优化,并提供了更多的API。
下⾯分析⼀理异步编程中的⼀些关键点
⼀、Await
我们都知道Await关键字是.NET FrameWork4.5引⼊的特性。
Await使得我们使⽤异步更加时特别便捷,并且还不会导致线程堵塞。
我们在使⽤时也就莫名其妙的使⽤。
往往不知道为什么不会导致线程堵塞。在这⾥,简单的谈论下Await的⼀点原理。
在C#并⾏编程这本书中是这么介绍await的:async⽅法在开始时以同步⽅式执⾏,在async⽅法内部,await关键字对它参数执⾏⼀个异步等待,它⾸先检查操作是否已经完成,如果完成,就继续运⾏(同步⽅式),否则,会暂停async⽅法,并返回.留下⼀个未完成的task⼀段时间后,操作完成,async⽅法就恢复执⾏.
看到这句话应该就差不多能想到await为什么不会导致线程堵塞了,当碰到await时如果没有执⾏成功就先暂停这个⽅法的执⾏,执⾏⽅法外以下代码,等await操作完成后再执⾏这个⽅法await之后的代码。
private void button1_Click(object sender, EventArgs e){
运⾏后会发现在点击button按钮时窗体不能被移动了,然后等待了3秒钟才弹出"同步代码"这句话。
async Task DemoAsync(){
await Task.Run(() => { Thread.Sleep(3000); });
Thread.Sleep(3000);
}
再次运⾏就会神奇的发现,此时会先弹出"同步代码"这句话,然后等待3秒后窗体就不能被移动。
⼆、Task
Task 类表⽰通常以异步⽅式执⾏的单个操作, Task 对象是基于任务的异步模式的中⼼组件之⼀。
由于 Task 对象执⾏的⼯作通常在线程池线程上异步执⾏,⽽不是在主应⽤程序线程上同步执⾏,因此可以使⽤ Status 属性,还可以使⽤IsCanceled、IsCompleted和 IsFaulted 属性,⽤于确定任务的状态。通常,lambda 表达式⽤于指定任务要执⾏的⼯作。可以通过多种⽅式创建 Task 实例。
最常见的⽅法(从 .NET Framework 4.5开始提供)是调⽤静态 Run ⽅法。Run ⽅法提供⼀种简单的⽅法来使⽤默认值启动任务,⽽⽆需其他参数。Task 类还提供了初始化任务的构造函数,但不计划执⾏该任务。
出于性能原因,Task.Run 或 TaskFactory.StartNew ⽅法是⽤于创建和计划计算任务的⾸选机制,但对于必须分隔创建和计划的情况,可以使⽤构造函数,然后调⽤ Task.Start⽤于计划任务稍后执⾏的⽅法。因为任务通常在线程池线程上以异步⽅式运⾏,所以,创建和启动任务的线程会在实例化任务后⽴即继续执⾏。
在某些情况下,当调⽤线程是主应⽤程序线程时,应⽤程序可能会在任何任务实际开始执⾏之前终⽌。在其他情况下,应⽤程序的逻辑可能要求调⽤线程在⼀个或多个任务完成执⾏时继续执⾏。
可以通过调⽤ Wait ⽅法来等待⼀个或多个任务完成,从⽽同步调⽤线程的执⾏以及它启动的异步任务。若要等待单个任务完成,可以调⽤其 Task.Wait ⽅法。
Wait(Int32) 和 Wait(TimeSpan) ⽅法会阻⽌调⽤线程,直到任务完成或超时间隔结束。
需要注意的是,Task中的⽅法⼀般是不会将异常抛出的,哪怕是Task这种,这需要开发⼈员⾃⾏处理。不过如果获取Task.Result则会将任务内的异常抛出来;
public static async Task<string> Hello(int a=0){
Task.Factory提供了更多参数的Task创建⽅式以⽀持⾃定义的Task,⽐如:Task,Factory.StartNew(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)就⽀持指定取消通知参数、任务创建模式,指定任务调度器;其中TaskCreationOptions参数意义如下:
三、Task.ConfigureAwait
在Task⾥中有ConfigureAwait这么⼀个⽅法,这个⽅法是⼲什么的呢,我们先看下⽅法注释是怎么解释这个⽅法的:"尝试将延续任务封送回原始上下⽂,则为 true;否则为 false"。光看这段代码并看不出什么,然后我们再看这么⼀段话:"⼀个async⽅法是由多个同步执⾏的程序块组成.每个同步程序块之间由await语句分隔.⽤await语句等待⼀个任务完成.当该⽅法在await处暂停时,就可以捕捉上下⽂(context).如果当前SynchronizationContext不为空,这个上下⽂就是当前SynchronizationContext.如果为空,则这个上下⽂为当前TaskScheduler.该⽅法会在这个上下⽂中继续运⾏.⼀般来说,运⾏UI线程时采⽤UI上下⽂,处理ASP.NET请求时采⽤ASP.NET请求上下⽂,其它很多情况则采⽤线程池上下⽂"。
这句话已经基本讲明了其实后续代码会下上⽂中执⾏。这个上下⽂⼀般是UI上下⽂(运⾏在UI上)或请求上下⽂(ASP.NET) 这两个可以说是原始上下⽂,⽽其它情况采⽤线程池上下⽂,也就是开辟⼀个新线程。这么说也就是ConfigureAwait⽅法是将后续代码是送到原始上下⽂还是线程池上下⽂中。
下⾯稍微修改下刚才的⽅法:
async Task DemoAsync()
ConfigureAwait(false)将后续代码交给线程池来执⾏,也就是上⾯的Thread.Sleep并不会阻塞窗体。
四、Task.Delay
在异步编程中,⼀般不建议使⽤Thread.Sleep,⽽是使⽤粒度更⼩的Task.Delay;Thread.Sleep、Thread.Yeild等会让当前⼯作线程阻塞,⽽Task.Delay可以让当前线程空出来去完成其他的Task。
new CancellationTokenSource();
五、SemaphoreSlim
表⽰对可同时访问资源或资源池的线程数加以限制的 Semaphore 的轻量替代, SemaphoreSlim类是⽤于在单个应⽤内进⾏同步的建议信号量。
在异步编程过程中,建议使⽤SemaphoreSlim.Wait()、SemaphoreSlim.Release()来替换Lock,因为lock只能由当前线程来解锁,⽽SemaphoreSlim可以由任意线程来解锁。
六、CancellationTokenSource
启动⼀个Task去做⼀些事,如果希望它在某个阶段去被动的停⽌,可以使⽤这个CancellationTokenSource对象,把它注⼊到Task⾥,使⽤当外界触发Cancel()⽅法或设置了超时时,这个Task就会被取消。
通常和CancellationToken.IsCancellationRequested⼀起配合Task来使⽤。
public static async void Loop(int timeOut = 5 * 1000){await和async使用方法
也可以CancellationTokenSource.CreateLinkedTokenSource来关联多个CancellationTokenSource
using (CancellationTokenSource cts =
七、TaskCompletionSource
表⽰未绑定到委托的 Task 的制造者⽅,并通过 Task 属性提供对使⽤者⽅的访问。
从这个官⽅解释上看不出这个到底有什么作⽤,其实这是⼀种受⽤者控制创建Task的⽅式。你可以使Task在任何你想要的时候完成,你也可以在任何地⽅给它⼀个异常让它失败。
这个可以实现事件通知类似的功能;具体就是说TaskCompletionSource如果不进⾏SetResult或SetException的时
候,TaskCompletionSource所委托的的Task是不会有Result,这个Task会⼀直等待TaskCompletionSource来赋值;这样就极⼤的简化了异步事件或异步通知的实现。
public static async Task<int> SetValue(int a = 1){
推荐阅读
(点击标题可跳转阅读)
.NET Core 3.0新增的异步流 (Async)
重新认识 Async/Await 语法糖
C#并发编程之异步编程(线程讨论)
看完本⽂有收获?请转发分享给更多⼈
关注「DotNet」加星标,提升.Net技能
好⽂章,我在看❤
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论