This answer says
by default the await operator will capture the current "context" and use that to resume the async method.
I am trying this code in my console app:
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!";
});
}
... and get this out:
Thread before: 1
Thread inside: 3
Hello stackoverflow!
Thread after: 3
Why? And also how I should set sync context if I want to use the same thread after await?
new SynchronizationContext()
by convention is the same as anull
SynchronizationContext
. Both "no SyncCtx" and "default SyncCtx" just queue work to the thread pool.There is not a 1:1 relationship between
SynchronizationContext
and a specific thread. For example:SynchronizationContext
will queue work to the single UI thread. AFAIK, the WinFormsSynchronizationContext
is a singleton, so there is a 1:1 mapping in this case.SynchronizationContext
will queue work to itsDispatcher
. Last time I checked, WPF will create a new instance for each top-level window, even if they all use the same thread. So there is a N:1 mapping.null
)SynchronizationContext
can queue work to any thread pool thread. If you don't create a defaultSynchronizationContext
instance, there is a 1:N mapping.You'll need to use a custom
SynchronizationContext
. I recommend using myAsyncContext
orAsyncContextThread
types, since that's not straightforward code to write.I am not an expert on this topic, I just have read some tutorials.
Code after
await
will be run as a task continuation with captured synchronization context. You providednew SynchronizationContext()
which usesThreadPool
to execute that code.Source code: link
Look at
Send
method inSynchronizationContext
class:So as you see, the continuation will not be run on
main
thread. It usesThreadPool
.When
GetResultAsync()
is done,thread 3
is free to use, and is immediately reused byThreadPool.QueueUserWorkItem
inSynchronizationContext
.So you need to create your own synchronization context for console application.
Didn't read, but maybe this link will help.