异步方法不能并行运行

Fer*_*lva 4 c# asynchronous task-parallel-library

在下面的代码中,在B方法中,代码为Trace.TraceInformation("B - Started"); 永远不会被召唤.

该方法应该并行运行吗?

using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private static async Task A()
        {
            for (;;)
            {
            }
        }


        private static async Task B()
        {
            Trace.TraceInformation("B - Started");
        }

        static void Main(string[] args)
        {
            var tasks = new List<Task> { A(), B() };
            Task.WaitAll(tasks.ToArray());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

oly*_*dis 9

简短的回答

不,当你编写两种async方法时,它们确实没有并行运行.添加await Task.Yield();到第一个方法(例如在循环内)允许它们这样做,但是有更合理和直接的方法,高度取决于您实际需要的内容(在单个线程上交错执行?在多个线程上实际并行执行?) .

答案很长

首先,声明函数async本身并不会使它们以异步方式运行.它相当简化了语法 - 阅读更多关于这里的概念:使用Async和Await进行异步编程

实际上A根本不是异步的,因为await它的方法体内没有一个.第一次使用await同步运行的说明就像常规方法一样.

从那时起,您await确定接下来发生的事情的对象,即剩余方法运行的上下文.

强制在另一个线程上执行任务,请使用Task.Run或类似.

在这种情况下,添加await Task.Yield()功能是因为当前的同步上下文是,null并且这确实导致任务调度程序(应该ThreadPoolTaskScheduler)执行线程池线程上的剩余安装 - 某些环境或配置可能导致您只有一个其中,事情仍然不会并行.

摘要

故事的寓意是:要意识到两个概念之间的差异:

  • 并发(通过使用async/ await合理地启用)和
  • 并行性(仅当并发任务以正确的方式进行调度时或者如果使用,等等强制执行它Task.Run时发生Thread,在这种情况下,使用async完全无关紧要)