await使用中的阻塞和并发

先看几个方法定义:

await使用中的阻塞和并发
        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);
        }
await使用中的阻塞和并发

作用很简单,仅仅是起到延迟的作用。我们再来看如下写法的调用

await使用中的阻塞和并发
            Console.WriteLine(DateTime.Now);
 
            new Action(async () =>
            {
                await Delay3000Async();
                await Delay2000Async();
                await Delay1000Async();
            })();        
await使用中的阻塞和并发

结果如图,可以看出3个await是线性执行,第一个await会返回并阻止接下来的await后面的方法。这应该不是我们想要的效果,毕竟后面的方法并不依赖第一个方法的执行。

await使用中的阻塞和并发

我们换一种写法,再运行一次程序:

await使用中的阻塞和并发
            var task3 = Delay3000Async();
            var task2 = Delay2000Async();
            var task1 = Delay1000Async();

            new Action(async () =>
            {
                await task3;
                await task2;
                await task1;
            })();    
await使用中的阻塞和并发

await使用中的阻塞和并发

可以看到3个await后面的方法是并行执行的。MSDN的解释如下:

In an async method, tasks are started when they’re created.  等待 (Visual Basic)或 等待 (C#)运算符应用于该点的任务在无法继续处理调用方法,直到任务完成。‘>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.

MSDN原文传送门

到这里并没有结束 ,后面还有一些奇怪的事情:

await使用中的阻塞和并发
            var tasks = new List<Task>
            {
                Delay3000Async(),
                Delay2000Async(),
                Delay1000Async()
            };

            tasks.ForEach(async _ => await _);
await使用中的阻塞和并发

这个结果和上面是一样的,可以并行执行。这并不奇怪,我们仅仅是把Task放到一个List里,按照MSDN的说法,Task在被我们放进List时就被创建,且并发执行了。

再来一个List,这回放进去的不是Task,而是Func<Task>:

await使用中的阻塞和并发
            var funcList = new List<Func<Task>>()
            {
                Delay3000Async,
                Delay2000Async,
                Delay1000Async
            };

            funcList.ForEach(async _ => await _());
await使用中的阻塞和并发

仍然可以并发执行,看上去似乎没什么问题,但是作为Func<Task>来存储到List里,应该是没有被创建出来才对。为什么会能够并发呢?

我们再来看最后一组写法:

await使用中的阻塞和并发
            Func<Task> func3 = Delay3000Async;
            Func<Task> func2 = Delay2000Async;
            Func<Task> func1 = Delay1000Async;

            new Action(async () =>
            {
                await func3();
                await func2();
                await func1();
            }
            )();
await使用中的阻塞和并发

意料之中的,以上的写法并不能够做到并发执行。而是需要按顺序执行func3,func2和func1。

await使用中的阻塞和并发

写到这里的时候已经开始迷糊了。参考了Reflector反编译的结果……我想说……没看出来有什么区别……本篇先到这里。一旦琢磨出个所以然,我再发第二篇好了。

还恭请各位高人不吝赐教,多多提点。

代码下载

await使用中的阻塞和并发

上一篇:谈谈vertical-align的text-bottom和text-top


下一篇:【语法】点语法的应用