简体   繁体   中英

Behavior of async await with new threads

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:

  1. 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?
  2. If the preceding is true, will the thread simply end and a thread pool thread take its place when the SomeOtherAsyncMethod returns?
  3. How would I go about issuing the StartThread function on a thread pool thread rather than a managed thread?
  4. 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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM