Eza*_*Eza 1 c# asynchronous async-await
任何人都可以准确地解释(或有资源解释)ThreadPool 线程何时被释放回 ThreadPool?这是一个小示例程序(Dotnet fiddle:https ://dotnetfiddle.net/XRso3q )
public static async Task Main()
{
Console.WriteLine("Start");
var t1 = ShortWork("SW1");
var t2 = ShortWork("SW2");
await Task.Delay(50);
var t3 = LongWork("LW1");
Console.WriteLine($"After starting LongWork Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(t1, t2);
await t3;
Console.WriteLine("Done");
}
public static async Task ShortWork(string name)
{
Console.WriteLine($"SHORT Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(500);
Console.WriteLine($"SHORT End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
public static async Task LongWork(string name)
{
Console.WriteLine($"LONG Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(2500);
Console.WriteLine($"LONG End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
Run Code Online (Sandbox Code Playgroud)
输出:
Start
SHORT Start SW1 Thread=1
SHORT Start SW2 Thread=1
LONG Start LW1 Thread=5
After starting LongWork Thread=5
SHORT End SW1 Thread=7
SHORT End SW2 Thread=5
LONG End LW1 Thread=5
Done
Run Code Online (Sandbox Code Playgroud)
长工作在线程 5 上开始,但在某个时刻,线程 5 被释放回线程池,因为线程 5 能够拾取短 SW1 结束。在 LongWork之后,5 到底什么时候被释放回线程池await Task.Delay(2500)
?调用是否将await
其释放回线程池?我不认为这种情况就像我在调用 后立即记录线程 id LongWork
,该线程仍在线程 5 上运行await Task.WhenAll
。 在线程 5 上调用 - 然后将控制释放回任何所谓的“main” - 这是哪里它被释放,因为没有“调用者”可以返回?
我对发生的事情的理解:
Task.Delay(50)
正在等待并且线程 1 被释放(因为没有更多的工作要做?)LongWork
,并且到达等待的2500ms
延迟。控制权被释放回主线程,仍在线程 5 上。t1
并t2
等待 - 控制权被释放回主线程(因此线程 5 的工作完成 - 它被释放到线程池)Task.WhenAll
另一个线程获取和 之间的延续await t3
,然后立即释放,因为它正在等待t3
LongWork
延续done
最后,ThreadPool 线程在 t3 完成后拾取最后要写入的工作。另外,为什么 5 会选取 SW1 的末尾,而 7 会选取 LW1 的末尾?这些是刚刚使用的线程。它们是否以某种方式保留为“热门线程并优先考虑出现的延续?”
其工作方式await
是首先检查其可等待的参数;如果已经完成,则该async
方法将同步继续。如果不完整,则该方法返回到其调用者。
理解的第二个关键是所有async
方法都像任何其他方法一样在正常调用堆栈上开始同步执行。
这里的第三个有用信息是控制台应用程序需要前台线程才能继续运行,否则它将退出。因此,当您有一个 时async Main
,运行时会在后台阻塞返回任务的主线程。因此,在您的示例中,当第一个await
被击中时Main
,它返回一个任务,并且主线程 1 将剩余的时间花在该任务上。
在此代码中,所有延续均由线程池线程运行。没有指定或保证哪个线程将运行哪个延续。
LONG Start LW1
当前的实现使用同步延续,因此在您的示例中,和的线程 idAfter starting LongWork
将始终相同。您甚至可以放置一个断点After starting LongWork
并查看LongWork
延续的调用堆栈中的实际情况Main
。
归档时间: |
|
查看次数: |
341 次 |
最近记录: |