【发布时间】:2021-12-27 14:45:56
【问题描述】:
我在这里是因为我在使用此代码时出现了一种奇怪的行为: 但在那之前,我知道这样做是一个非常糟糕的做法,所以它甚至没有在现实中使用我只是想了解幕后发生的事情,但我的知识真的很差。
这是有问题的代码:
int worker = 0;
int io = 0;
Console.WriteLine($"Worker thread {worker} Io thread {io}");
ThreadPool.GetAvailableThreads(out worker, out io);
ThreadPool.GetMaxThreads(out var workerThreadsMax, out var completionPortThreadsMax);
Console.WriteLine($"Worker thread {workerThreadsMax - worker} Io thread {completionPortThreadsMax - io}");
for (int i = 0; i < 100; i++)
{
Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - Running thread");
ThreadPool.GetAvailableThreads(out var worker2, out var io2);
ThreadPool.GetMaxThreads(out var workerThreadsMax2, out var completionPortThreadsMax2);
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} - Worker thread {workerThreadsMax2 - worker2} Io thread {completionPortThreadsMax2 - io2}");
var t1 = Task.Delay(5000);
var t2 = Task.Delay(5000);
Task.WaitAll(t1, t2);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - End of thread");
ThreadPool.GetAvailableThreads(out worker2, out io2);
ThreadPool.GetMaxThreads(out workerThreadsMax2, out completionPortThreadsMax2);
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} - Worker thread {workerThreadsMax2 - worker2} Io thread {completionPortThreadsMax2 - io2}");
});
}
Console.ReadLine();
所以我在这段代码中试图做的是运行或至少排队 500 个任务(我知道很多,但很好奇),同时仍然显示来自 ThreadPool 的活动线程的数量。所以在第一行中,我在 ThreadPool 中有 0 个工作线程,这是有道理的,只要我还没有启动任何任务。但是当第一个任务运行时,有 8 个活动线程。这里发生了一件奇怪的事情: 每秒或更少产生一个新线程(但不是立即产生),这不是一个真正的问题,但我不明白为什么任务被阻止?即使完成了 250 毫秒的延迟,任务也不会自行结束,即使超过一分钟,它仍然会阻塞在 Task.WaitAll 线上:
Worker thread 0 Io thread 0
Worker thread 0 Io thread 0
8 - Running thread
8 - Worker thread 8 Io thread 0
6 - Running thread
6 - Worker thread 8 Io thread 0
10 - Running thread
10 - Worker thread 8 Io thread 0
7 - Running thread
7 - Worker thread 8 Io thread 0
11 - Running thread
11 - Worker thread 8 Io thread 0
5 - Running thread
9 - Running thread
9 - Worker thread 8 Io thread 0
12 - Running thread
12 - Worker thread 8 Io thread 0
5 - Worker thread 8 Io thread 0
13 - Running thread
13 - Worker thread 9 Io thread 0
14 - Running thread
14 - Worker thread 10 Io thread 0
15 - Running thread
15 - Worker thread 11 Io thread 0
16 - Running thread
16 - Worker thread 12 Io thread 0
17 - Running thread
17 - Worker thread 13 Io thread 0
18 - Running thread
18 - Worker thread 14 Io thread 0
这里是否发生了死锁?如果有人可以向我解释这一点,那就太好了。谢谢。
编辑:对于那些建议使用 async 和 await Task.WhenAll(..) 的人,你是完全正确的!但正如我所说,这是出于测试目的,我不会在现实中这样做,而是使用 async/await 语句。但是我们正在和朋友一起测试一些关于同步和异步任务的东西,在测试同步方式时,我们遇到了这个问题,但不知道发生了什么。感谢那些澄清这一点的人。很有启发性。
【问题讨论】:
-
应该是
await Task.WaitAll(....)。你需要让你的方法async释放线程 -
@Liam
WaitAll不是等待超载 AFAIK。 -
好的,应该是
WhenAll -
顺便说一句,你在谈论“500 个任务”的问题,但循环是
for (int i = 0; i < 100; i++)。您也在谈论“250ms 延迟”,但我能看到的唯一延迟是Task.Delay(5000)。 -
这与死锁相反,您会看到线程池管理器试图解决这些未及时完成的线程并卡在 WaitAll() 调用上。它不知道为什么他们没有取得进展并假设它可能是由死锁引起的,允许额外的线程运行可以解决问题。对于耗时超过半秒的任务,您应该使用 TaskCreationOptions.LongRunning 选项。副作用是它现在使用常规线程而不是 tp 线程,并且不再受到池规则的限制。
标签: c# async-await task