谁在 Async Await 上下文中运行 awaitable

Who runs the awaitable in an Async Await context

我一直在阅读,我注意到 Async/Await 在 I/O 或任何其他硬件组件上运行时不一定会创建新线程。

但是当操作 CPU 绑定时会发生什么?

    public partial class Form1 : Form
    {
        private static List<string> _logs = new List<string>();

        public Form1()
        {
            Print("Form constructor");
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            Print("Caller");
            await SomeLongOperation();
        }

        private async Task SomeLongOperation()
        {
            Print("Called");
            await Task.Delay(10000);
            Print("Called after task");
        }

        public void Print(string txt)
        {
            _logs.Add($"I'm writing from thread {Thread.CurrentThread.ManagedThreadId}. And, {txt}");
        }
    }

假设我有这个class,如果主线程调用button1_Click方法运行到等待,然后方法的其余部分在消息循环中排队,因此允许主线程继续工作,那么谁是 运行 等待对象,因为主线程已经在 UI 上工作并等待等待对象完成。

asyncawait 关键字实际上不会导致额外创建线程。异步方法不需要多线程,因为异步方法不会 运行 在它自己的线程上。该方法实际上 运行 占用当前同步上下文,并且仅在该方法处于活动状态时 使用线程上的时间 。开发人员可以使用 Task.Run 将 CPU 绑定的工作任务移动到后台线程。话虽如此,后台线程对只是等待结果可用的进程没有帮助。

有关 async/await 和线程的更多信息,请参见此处 - https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-2.2#automatic-http-400-responses -

我认为您混淆了“异步”和“并行”。

  • 异步意味着线程在等待其他事情的同时被释放出来做其他事情。这是关于你的代码如何 waits.
  • 并行是指代码的两部分同时 运行ning。这只能通过多线程来完成。这是关于你的代码如何 运行s.

您的示例代码是异步的,但不是并行的。一切都在一个线程上完成。 Task.Delay 不是 CPU 操作。线程无事可做。 There is no thread.

如果您确实对 运行 进行了一些 CPU 密集型操作,您可以使用 Task.Run 将其卸载到另一个线程。例如:

await Task.Run(() => DoSomethingIntensive());

这混合了异步和并行的概念。 DoSomethingIntensive() 在单独的线程上是 运行。那是平行的。但是主线程是异步等待的,这意味着它可以在等待另一个线程做它的事情的同时自由地去做其他事情(比如响应用户输入)。