我正在尝试了解async / await的精确行为,并且在绕过它的过程中遇到了一些麻烦。
考虑这个例子:
public async void StartThread()
{
while(true){
SomeOtherClass.SomeSynchronousStuff();
var something = await SomeOtherClass.SomeOtherAsyncMethod();
}
}
public void ConstructorForThisClass()
{
Thread thread = new Thread(StartThread);
thread.Start();
}
我对async / await的理解是,幕后发生的事情是编译器本质上是将你的代码转换成一堆回调并为每一个回存存储状态对象。
所以根据这个,我的问题是:
SomeOtherAsyncMethod
时,它是否会被释放以用于其他工作?SomeOtherAsyncMethod
返回时,线程是否会结束并且线程池线程会取代它?StartThread
函数?答案 0 :(得分:5)
新创建的线程是否会异步运行?
你的措辞有点问题。线程的创建是完全同步的。
意思是,当线程正在等待SomeOtherAsyncMethod时,它会是什么 腾出来从事其他工作?
您使用Thread
类手动创建线程,而不是Threadpool线程。它不在AppDomain中共享。一旦它到达第一个await
关键字, 就会被释放,但由于你在无休止的while
循环中使用它,它将不会被用于其他任何其他工作不止于此。
如果前面的条件为真,那么线程是否会结束并且是一个线程池 当SomeOtherAsyncMethod返回时,线程取代它?
忽略前者,因为你不使用ConfigureAwait(false)
,所以继续将在任意ThreadPool线程上运行。但这实际上取决于背景。由于您在新线程上运行此委托,所以会发生这种情况。但是,如果你是从UI线程运行这个,那么继续尝试通过相关的TaskScheduler
和相应的SynchronizationContext
将自己封送到UI消息循环。
我如何在线程池上发布StartThread函数 线程而不是托管线程?
Thread
类和ThreadPool
类启动的所有线程都是托管线程。如果你的意思是“如何在线程池上运行此委托”,那么答案是通过Task.Run
或通过ThreadPool
静态类。
当一个等待的方法返回其调用者时,它是否被迫恢复 在调用它的线程上还是可以使用任何自由线程取代它?
如果在没有ConfigureAwait(false)
的情况下投放,则会将其强制转移到当前TaskScheduler
及其基础SynchronizationContext
。这意味着如果您在UI消息循环内运行,并在那里调用await
,它将尝试将延续发布到它。如果没有自定义TaskScheduler
可用,它将使用默认的一个,即线程池调度程序。
答案 1 :(得分:5)
使用async
/ await
时,裸线程无效。
新创建的线程是否会异步运行?意思是,当线程正在等待SomeOtherAsyncMethod时,它是否会被释放以用于其他工作?
实际上,线程将退出。当StartThread
在await
之后恢复时,它将在线程池线程上执行。
我如何在线程池线程而不是托管线程上发布StartThread函数?
首先,您需要将StartThread
的返回类型从void
更改为Task
。 async void
方法适用于事件处理程序;在其他地方使用它们会导致各种各样的问题。
然后你可以通过Task.Run
:
var backgroundTask = Task.Run(() => StartThread());
当一个等待的方法返回给它的调用者时,是否强制它在调用它的线程上恢复,或者任何空闲的线程可以取而代之?
默认情况下,await
运算符将捕获“当前上下文”并在该上下文中恢复 。这个“当前上下文”是SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。通常,这是UI / ASP.NET SynchronizationContext
,否则就是线程池上下文(TaskScheduler.Default
)。
您可能会发现我的async
intro有帮助。