问题
I am trying to understand the precise behavior of async/await and am having a small amount of trouble wrapping my head around it.
Consider this example:
public async void StartThread()
{
while(true){
SomeOtherClass.SomeSynchronousStuff();
var something = await SomeOtherClass.SomeOtherAsyncMethod();
}
}
public void ConstructorForThisClass()
{
Thread thread = new Thread(StartThread);
thread.Start();
}
My understanding of async/await is that what is happening under the covers is that the compiler is essentially turning your code into a bunch of callbacks and storing state objects for each one.
So according to this, my questions are:
- Will the newly created thread be running asynchronously? Meaning, while the thread is awaiting the
SomeOtherAsyncMethod
, will it be freed up to work on other work? - If the preceding is true, will the thread simply end and a thread pool thread take its place when the
SomeOtherAsyncMethod
returns? - How would I go about issuing the
StartThread
function on a thread pool thread rather than a managed thread? - When an awaitable method returns to its caller, is it forced to resume on the thread that calls it or can any free thread take its place?
回答1:
Will the newly created thread be running asynchronously?
Your wording is a bit problematic. The creation of the thread is completely synchronous.
Meaning, while the thread is awaiting the SomeOtherAsyncMethod, will it be freed up to work on other work?
You're manually creating a thread using the Thread
class, not a Threadpool Thread. It isn't shared inside the AppDomain. It will be freed up once it hits the first await
keyword, but since you use it in an endless while
loop, it won't get used for any other work other than that.
If the preceding is true, will the thread simply end and a thread pool thread take its place when the SomeOtherAsyncMethod returns?
Disregarding the former, since you don't use ConfigureAwait(false)
, then the continuation will run on an arbitrary ThreadPool thread. But that really depends on the context. Since you're running this delegate on a new Thread, that's what happens. But if you were, say, run this from the UI thread, then the continuation would of attempted to marshal itself to the UI message loop via the relevant TaskScheduler
and the corresponding SynchronizationContext
.
How would I go about issuing the StartThread function on a thread pool thread rather than a managed thread?
All threads initiated by the Thread
class and the ThreadPool
class are managed threads. If you meant "How do i run this delegate on the threadpool", than the answer is via Task.Run
or via the ThreadPool
static class.
When an awaitable method returns to its caller, is it forced to resume on the thread that calls it or can any free thread take its place?
If ran without ConfigureAwait(false)
, it is forced onto the current TaskScheduler
and its underlying SynchronizationContext
. This means that if you run inside a UI message loop, and call await
there, it will attempt to post the continuation to it. If no custom TaskScheduler
is available, it will use the default one, which is the threadpools scheduler.
回答2:
Bare threads don't work great with async
/await
.
Will the newly created thread be running asynchronously? Meaning, while the thread is awaiting the SomeOtherAsyncMethod, will it be freed up to work on other work?
Actually, the thread will just exit. When StartThread
resumes after the await
, it will execute on a thread pool thread.
How would I go about issuing the StartThread function on a thread pool thread rather than a managed thread?
First, you'd want to change the return type of StartThread
from void
to Task
. async void
methods are intended for event handlers; using them in other places can cause all sorts of problems.
Then you can just call it via Task.Run
:
var backgroundTask = Task.Run(() => StartThread());
When an awaitable method returns to its caller, is it forced to resume on the thread that calls it or can any free thread take its place?
By default, the await
operator will capture the "current context" and resume on that context. This "current context" is SynchronizationContext.Current
, unless it is null
, in which case it is TaskScheduler.Current
. Usually, this is either a UI/ASP.NET SynchronizationContext
, or else it's the thread pool context (TaskScheduler.Default
).
You may find my async intro helpful.
来源:https://stackoverflow.com/questions/29151168/behavior-of-async-await-with-new-threads