好吧,不加点陈述不让发首页。那咱们来陈述一下本篇提到的问题和对应的方法。html
在.NET4.5中,咱们能够配合使用async和await两个关键字,来以写同步代码的方式,实现异步的操做。web
好处我目前看来有两点:并发
1.不会阻塞UI线程。一旦UI线程不能及时响应,会极大的影响用户体验,这点在手机和平板的APP上尤其重要。app
2.代码简洁。异步
在同一个方法里存在多个await的状况下,如后续Async方法无需等待以前的Aysnc方法返回的结果,会隐式的以并行方式来运行后面的Async方法。async
值得注意的是错误的写法会致使非预期的阻塞,下文会以简单的例子来讨论在使用await的状况下,怎样实现多个Task的并发执行。优化
咱们这里先看几个方法定义:ui
static async Task Delay3000Async() { await Task.Delay(3000); Console.WriteLine(3000); Console.WriteLine(DateTime.Now); } static async Task Delay2000Async() { await Task.Delay(2000); Console.WriteLine(2000); Console.WriteLine(DateTime.Now); } static async Task Delay1000Async() { await Task.Delay(1000); Console.WriteLine(1000); Console.WriteLine(DateTime.Now); }
做用很简单,仅仅是起到延迟的做用。咱们再来看以下写法的调用spa
Console.WriteLine(DateTime.Now); new Action(async () => { await Delay3000Async(); await Delay2000Async(); await Delay1000Async(); })();
结果如图,能够看出3个await是线性执行,第一个await会返回并阻止接下来的await后面的方法。这应该不是咱们想要的效果,毕竟后面的方法并不依赖第一个方法的执行。线程
咱们换一种写法,再运行一次程序:
var task3 = Delay3000Async(); var task2 = Delay2000Async(); var task1 = Delay1000Async(); new Action(async () => { await task3; await task2; await task1; })();
能够看到3个await后面的方法是并行执行的。MSDN的解释以下:
In an async method, tasks are started when they’re created. The Await (Visual Basic) or await (C#) operator is applied to the task at the point in the method where processing can’t continue until the task finishes.
However, you can separate creating the task from awaiting the task if your program has other work to accomplish that doesn’t depend on the completion of the task.
Between starting a task and awaiting it, you can start other tasks. The additional tasks implicitly run in parallel, but no additional threads are created.
到这里并无结束 ,后面还有一些奇怪的事情:
var tasks = new List<Task> { Delay3000Async(), Delay2000Async(), Delay1000Async() }; tasks.ForEach(async _ => await _);
这个结果和上面是同样的,能够并行执行。这并不奇怪,咱们仅仅是把Task放到一个List里,按照MSDN的说法,Task在被咱们放进List时就被建立,且并发执行了。
那么咱们再来一个List,这回放进去的不是Task,而是Func<Task>:
var funcList = new List<Func<Task>>() { Delay3000Async, Delay2000Async, Delay1000Async }; funcList.ForEach(async _ => await _());
仍然能够并发执行,看上去彷佛没什么问题,可是做为Func<Task>来存储到List里,应该是没有被建立出来才对。为何会可以并发呢?
咱们再来看最后一组写法:
Func<Task> func3 = Delay3000Async; Func<Task> func2 = Delay2000Async; Func<Task> func1 = Delay1000Async; new Action(async () => { await func3(); await func2(); await func1(); } )();
意料之中的,以上的写法并不可以作到并发执行。而是须要按顺序执行func3,func2和func1。这很好解释,由于: a task is awaited as soon as it’s created。咱们在建立Task以后当即就要求阻塞并等待完成才进行下一步。
写到这里的时候对List<Func<Task>>的例子开始迷糊了。参考了Reflector反编译的结果……我想说……没看出来有什么区别……本篇先到这里。一旦琢磨出个因此然,我再发第二篇好了。
还恭请各位高人不吝赐教,多多提点。
补充:对List<Func<Task>>的那个例子,我怀疑是Foreach这个扩展方法在偷偷作了优化。故增长了以下的试验:
static async Task TestForeach() { var funcList = new List<Func<Task>>() { Delay3000Async, Delay2000Async, Delay1000Async }; foreach (var item in funcList) {
//这里干了件蠢事,不要主动阻塞在这里,就能够并发了…… await item(); } }
试验结果代表用foreach来写的话,确实是作不到并行执行的。那么就须要去看一下Foreach的背后到底发生了什么。我还要研究研究才能写下一篇……
哈哈哈哈,干了件蠢事情……