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)
我有一个等待,ConfigureAwait 设置为 false,所以我理解了它是一个任务延续之后的代码,它假设在与等待之前的代码不同的线程中运行(因为ConfigureAwait 设置为 false)。
不,这里有一些误解。
第一个误解是关于ConfigureAwait(false)做什么的。
ConfigureAwait( 和await) 与线程直接无关。默认情况下,await捕获上下文- 当前SynchronizationContext或TaskScheduler. 此上下文可以在同一线程上恢复(例如,UISynchronizationContext通常执行此操作),但“上下文”不一定意味着“线程”(例如,ASP.NET pre-Core可以在任何线程池线程SynchronizationContext上恢复)。
实际上所做ConfigureAwait(false)的是跳过捕获该上下文。因此使用了线程池上下文,它可以运行在任何线程池线程上。请注意,如果之前的代码await在线程池线程上运行,则它可以在任何线程池线程上恢复,包括之前运行的线程。
第二个误解是关于何时ConfigureAwait(false)应用。
await首先会检查它的等待是否完成,只有这样它才会真正异步运行。因此,如果您await已经完成了任务,则ConfigureAwait(false)根本不会考虑 - 代码只是继续同步运行。
那么我怎样才能强制它在不同的线程上运行呢?
使用Task.Run。Task.Run当您需要在线程池线程上运行代码时,这是正确的工具。
它不是“应该在不同的线程上下文中运行”,而是允许的。在相反的情况下 ( ConfigureAwait(true)) 它必须在同一个线程上下文中继续。
此外,当没有任何等待(在方法内部)时,“async”方法同步运行,因此不需要返回某个线程上下文,它仍在它上面。