异步方法在哪里运行?

时间:2013-12-06 14:26:35

标签: .net asynchronous threadpool async-await

我已经阅读了很多关于async-await模式的文章,但我仍然不确定是否在UI线程上运行异步方法(等待的方法)。 我总是最终使用SynchronizationContext类“异步方法在与被调用者相同的SynchronizationContext中运行”这究竟意味着什么?

是新创建的单独线程(我知道它不是)还是ThreadPool线程?

当我读取SynchronizationContext时,我发现它是某种排队的任务执行者,但这些任务在哪里执行?在ThreadPool上?

如果是,则在ThreadPool上执行异步方法,对吗?

2 个答案:

答案 0 :(得分:4)

标记为async的方法在调用它的线程上运行,直到它到达其中的第一个await关键字。

但有一个例外:如果等待的方法在到达await关键字时已经完成运行,那么执行只会在不切换线程的情况下继续执行。

public async Task Method()
{
    Console.WriteLine(1);
    await Something();
    Console.Writeline(2);
}

在这种情况下,如果在线程A上调用该方法,则也将从线程A打印1。

然后你转到下一条指令。 如果Task返回的something已经完成,则在线程A上继续执行。 如果Task返回的something仍在运行,则可以从以下任一位置打印出来:

  1. 线程A再次 - 如果有一个SynchronizationContext强制执行此操作(如在WPF或WinRT应用程序中)。简单地说,这是通过排队和调度要在线程A上执行的剩余代码(即第三条指令)来完成的。
  2. 在一个完全不同的主题B上。

  3. 关于你对ThreadPool的怀疑:

    正如我们所见,async方法不能保证在ThreadPool上运行。 只有Task.Run重载方法之一安排的工作肯定会在ThreadPool上运行。 引用Task MSDN doc:

      

    将指定的工作排队到ThreadPool上并返回该工作的任务句柄。

    public void Task Something()
    {
        return Task.Run(() => Console.WriteLine(3));
    }
    

    3将由ThreadPool上的一个线程打印。

答案 1 :(得分:3)

  

我已经阅读了很多关于async-await模式的文章,但我仍然不确定异步方法(等待的方法)是否在UI线程上运行。

如果您还没有,请查看我的async intro post,其中解释了asyncawait的线索行为。

当您调用async方法时,它会在第一次await未完成的操作时同步执行。然后async方法捕获当前的“上下文”并调度其余部分以便稍后执行,然后返回。

稍后,当操作完成时,async方法的其余部分将安排在捕获的“上下文”上运行。

“上下文”是当前SynchronizationContext,除非它是null,在这种情况下,它是当前TaskScheduler。当您从UI线程调用async方法时,您有一个UI SynchronizationContext,它通过将工作发布到UI线程的消息循环来工作。