默认情况下,await运算符将捕获当前" context"并使用它来恢复异步方法。
我正在我的控制台应用中尝试此代码:
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!";
});
}
...并解决这个问题:
Thread before: 1
Thread inside: 3
Hello stackoverflow!
Thread after: 3
为什么呢?如果我想在等待之后使用相同的线程,我还应该如何设置同步上下文?
答案 0 :(得分:4)
为什么?
new SynchronizationContext()
by convention与null
SynchronizationContext
相同。两者都没有&#34;没有SyncCtx&#34;和&#34;默认的SyncCtx&#34;只是将工作排队到线程池。
SynchronizationContext
与特定线程之间没有1:1的关系。例如:
SynchronizationContext
将工作排队到单个UI线程。 AFAIK,WinForms SynchronizationContext
是一个单例,因此在这种情况下有一个1:1映射 。SynchronizationContext
会将工作排到其Dispatcher
。上次我检查时,WPF将为每个顶级窗口创建一个新的实例,即使它们都使用相同的线程。所以有一个N:1映射。null
)SynchronizationContext
可以将工作排入任何线程池线程。如果您没有创建默认的SynchronizationContext
实例,则会有1:N映射。如果我想在等待之后使用相同的线程,我还应该如何设置同步上下文?
您需要使用自定义SynchronizationContext
。我建议使用我的AsyncContext
or AsyncContextThread
types,因为这不是简单的代码。
答案 1 :(得分:1)
我不是这方面的专家,我刚读了一些教程。
await
之后的代码将作为具有捕获的同步上下文的任务继续运行。您提供了使用new SynchronizationContext()
来执行该代码的ThreadPool
。
源代码:link
查看Send
类中的SynchronizationContext
方法:
public virtual void Post(SendOrPostCallback d, Object state)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
}
如您所见,继续不会在main
线程上运行。它使用ThreadPool
。
完成GetResultAsync()
后,thread 3
可以免费使用,ThreadPool.QueueUserWorkItem
中的SynchronizationContext
会立即重复使用{。}}。
因此,您需要为控制台应用程序创建自己的同步上下文。
没看过,但也许这个link会有所帮助。