ConfigureAwait(false) 不会使继续代码在另一个线程中运行

S I*_*zik 0 .net c# multithreading async-await configureawait

我有一个在thread1上运行的代码。我以同步方式调用函数(使用异步方法,但它不应该打扰我 - 异步方法不会将代码变为异步)。

我有一个等待,ConfigureAwait 设置为 false,所以我理解了它是一个任务延续之后的代码,它假设与等待之前的代码不同的线程中运行(因为 ConfigureAwait 被设置为 false)。

通过我的测试 - 所有代码都在同一个线程中运行。如何?为什么等待下面的代码不在不同的线程上运行?这是代码:

public async void F1()
{
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    int x = await F2().ConfigureAwait(false);
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}

private async Task<int> F2()
{
    Console.WriteLine("Begins F2");
    Console.WriteLine($"Thread.CurrentThread.ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.WriteLine("Finishes F2");
    return 7;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

Thread.CurrentThread.ManagedThreadId=1
Begins F2
Thread.CurrentThread.ManagedThreadId=1
Finishes F2
Thread.CurrentThread.ManagedThreadId=1
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 9

我有一个等待,ConfigureAwait 设置为 false,所以我理解了它是一个任务延续之后的代码,它假设在与等待之前的代码不同的线程中运行(因为ConfigureAwait 设置为 false)。

不,这里有一些误解。

第一个误解是关于ConfigureAwait(false)做什么的。

ConfigureAwait( 和await) 与线程直接无关。默认情况下,await捕获上下文- 当前SynchronizationContextTaskScheduler. 此上下文可以在同一线程上恢复(例如,UISynchronizationContext通常执行此操作),但“上下文”不一定意味着“线程”(例如,ASP.NET pre-Core可以在任何线程池线程SynchronizationContext上恢复)。

实际上所做ConfigureAwait(false)的是跳过捕获该上下文。因此使用了线程池上下文,它可以运行在任何线程池线程上。请注意,如果之前的代码await在线程池线程上运行,则它可以在任何线程池线程上恢复,包括之前运行的线程。

第二个误解是关于何时ConfigureAwait(false)应用。

await首先会检查它的等待是否完成只有这样它才会真正异步运行。因此,如果您await已经完成了任务,则ConfigureAwait(false)根本不会考虑 - 代码只是继续同步运行。

那么我怎样才能强制它在不同的线程上运行呢?

使用Task.RunTask.Run当您需要在线程池线程上运行代码时,这是正确的工具。


Han*_*ing 5

它不是“应该在不同的线程上下文中运行”,而是允许的。在相反的情况下 ( ConfigureAwait(true)) 它必须在同一个线程上下文中继续。

此外,当没有任何等待(在方法内部)时,“async”方法同步运行,因此不需要返回某个线程上下文,它仍在它上面。

  • 它不必在同一线程上继续,它必须在同一上下文中继续。例如,经典的 ASP.Net 同步上下文不能保证您将获得哪个线程,只是它具有对请求等内容的独占访问权限。 (2认同)