Behavior of async await with new threads

孤街醉人 提交于 2021-02-04 19:31:38

问题


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?

回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!