使用此代码:
static void Main(string[] args)
{
Console.WriteLine("Main Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
Task.Run(() => AsyncMethod()).Wait();
Console.WriteLine("Main Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
Console.ReadKey();
}
static async Task AsyncMethod()
{
Console.WriteLine("AsyncMethod Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
await Task.Delay(4000).ConfigureAwait(false);
Console.WriteLine("AsyncMethod Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
}
输出结果为:
Main Thread Pre - 8652
AsyncMethod Thread Pre - 4764
AsyncMethod Thread Post - 1768
Main Thread Post - 8652
使用Concurrency Visualizer,我可以看到在4秒延迟期间,线程4764卡在同步中。它最终在关机时被主线程解锁。
线程4764一旦到达ThreadPool
,是否应该返回await
? (据说我不知道在Concurrency Visualizer中会是什么样子)
答案 0 :(得分:4)
一旦线程4764到达等待点,它是否应该返回到ThreadPool?
是。它就是。
(据说我不知道在Concurrency Visualizer中会是什么样子)
这很容易检查。只需在线程池中显式执行一些代码,并在可视化器不忙时查看该线程的样子。
例如:
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine("worker: " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
Thread.Sleep(250);
});
(我添加了睡眠,因此它在可视化工具中更容易显示为做了一些事情:))。
当你这样做时,你会发现它看起来就像你所看到的一样。 :)
当我运行它时,线程池甚至使用了与原始Task
相同的工作线程。并且您可以看到线程池工作线程在等待更多工作时处于Synchronization
状态。
哪个有道理。在抽象层面,线程池的作用是什么?重点是它拥有已经存在的线程。但是你不希望那些线程实际上在那里工作,除非他们有一些工作要做。这会毫无理由地燃烧CPU时间。因此,他们等待同步对象。
当某些内容(如Task
)想要使用一个时,它会将一个工作项排队,然后线程池向该线程发出信号,表明它有事可做。这会唤醒线程,它会完成它的工作,然后再次阻塞同步对象,等待其他事情去做。
如果检查相关线程的调用堆栈,您将看到工作线程正在等待对WaitForSingleObject()
的调用,并且您将看到线程池最终取消阻塞线程使用ReleaseSemaphore()
。
正如您所见,这显示为线程池线程的Synchronization
状态。