【发布时间】:2023-03-20 15:38:01
【问题描述】:
阅读Stephen Toub's article on SynchronizationContext 后,我对这段 .NET 4.5 代码的输出有疑问:
private void btnDoSomething_Click()
{
LogSyncContext("btnDoSomething_Click");
DoItAsync().Wait();
}
private async Task DoItAsync()
{
LogSyncContext("DoItAsync");
await PerformServiceCall().ConfigureAwait(false); //to avoid deadlocking
}
private async Task PerformServiceCall()
{
LogSyncContext("PerformServiceCall 1");
HttpResponseMessage message = await new HttpClient
{
BaseAddress = new Uri("http://my-service")
}
.GetAsync("/").ConfigureAwait(false); //to avoid deadlocking
LogSyncContext("PerformServiceCall 2");
await ProcessMessage(message);
LogSyncContext("PerformServiceCall 3");
}
private async Task ProcessMessage(HttpResponseMessage message)
{
LogSyncContext("ProcessMessage");
string data = await message.Content.ReadAsStringAsync();
//do something with data
}
private static void LogSyncContext(string statementId)
{
Trace.WriteLine(String.Format("{0} {1}", statementId, SynchronizationContext.Current != null ? SynchronizationContext.Current.GetType().Name : TaskScheduler.Current.GetType().Name));
}
输出是:
btnDoSomething_Click WindowsFormsSynchronizationContext
DoItAsync WindowsFormsSynchronizationContext
PerformServiceCall 1 WindowsFormsSynchronizationContext
PerformServiceCall 2 线程池任务调度器
ProcessMessage ThreadPoolTaskScheduler
PerformServiceCall 3 线程池任务调度器
但我希望 PerformServiceCall 1 不会出现在 WindowsFormsSynchronizationContext 上,因为文章指出“SynchronizationContext.Current 不会跨等待点“流动”...
使用 Task.Run 和异步 lambda 调用 PerformServiceCall 时,上下文不会被传递,如下所示:
await Task.Run(async () =>
{
await PerformServiceCall();
}).ConfigureAwait(false);
任何人都可以澄清或指出一些关于此的文档吗?
【问题讨论】:
-
在任务实际开始等待之前,ConfigureAwait() 调用不会产生任何影响。那还没有发生,您的 LogSyncContext() 调用太早了。在等待之后移动它。
-
这不是在`DoItAsync().Wait();`上死锁吗?
-
不,由于 ConfigureAwait 调用,它没有死锁
标签: c# .net async-await synchronizationcontext