为什么同步上下文不适用于等待?

hcp*_*hcp 3 c# asynchronous async-await

这个答案

默认情况下,await 运算符将捕获当前的“上下文”并使用它来恢复异步方法。

我正在我的控制台应用程序中尝试此代码:

static void Main(string[] args)
{
    Test().Wait();
}

private static async Task Test()
{
    var context = new SynchronizationContext();
    SynchronizationContext.SetSynchronizationContext(context);
    Console.WriteLine("Thread before: " + Thread.CurrentThread.ManagedThreadId);
    Console.WriteLine(await GetResultAsync());
    Console.WriteLine("Thread after: " + Thread.CurrentThread.ManagedThreadId);
}

private static async Task<string> GetResultAsync()
{
    return await Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Thread inside: " + Thread.CurrentThread.ManagedThreadId);
        return "Hello stackoverflow!";
    });
}
Run Code Online (Sandbox Code Playgroud)

......然后把它弄出来:

Thread before: 1
Thread inside: 3
Hello stackoverflow!
Thread after: 3
Run Code Online (Sandbox Code Playgroud)

为什么?如果我想在等待后使用相同的线程,我应该如何设置同步上下文?

Ste*_*ary 5

为什么?

new SynchronizationContext() 按照惯例是一样的null SynchronizationContext。“no SyncCtx”和“default SyncCtx”都只是将工作排入线程池。

SynchronizationContext和特定线程之间没有 1:1 的关系。例如:

  • WinForms UISynchronizationContext会将工作排队到单个 UI 线程。AFAIK,WinFormsSynchronizationContext是一个单例,所以在这种情况下有一个 1:1 映射。
  • WPFSynchronizationContext会将工作排队到其Dispatcher. 上次检查时,WPF 将为每个顶级窗口创建一个新实例,即使它们都使用相同的线程。所以有一个 N:1 映射。
  • 线程池(默认/ nullSynchronizationContext可以将工作排队到任何线程池线程。如果您不创建默认SynchronizationContext实例,则存在 1:N 映射。

如果我想在等待后使用相同的线程,我应该如何设置同步上下文?

您需要使用自定义SynchronizationContext. 我建议使用 myAsyncContextAsyncContextThreadtypes,因为这不是编写简单的代码。