我们的应用程序创建许多在CLR线程池上运行的任务。 任务数量可能从10到10万。
当任务数量快速增加时,许多任务无法在给定时间内完成。
这是因为线程池每秒只添加一个新线程(尽管可能有数百个等待任务)。
以下测试说明了问题:
[Test]
public void TestTasks()
{
ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(1, 1);
var source = new CancellationTokenSource();
for (int i=0; i<1000; i++)
{
int ci = i;
Task.Run(() => {
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + $" {ci} - START");
Thread.Sleep(TimeSpan.FromSeconds(5)); // long operation simulatation
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff") + $" {ci} - FINISH");
}, source.Token);
}
Thread.Sleep(TimeSpan.FromSeconds(10));
source.Cancel();
}
典型输出
01:38:37.171 0 - START
01:38:37.171 1 - START
01:38:37.172 2 - START
01:38:37.172 3 - START
01:38:38.029 4 - START
01:38:39.029 5 - START
01:38:40.030 6 - START
01:38:41.031 7 - START
01:38:42.029 8 - START
01:38:42.172 0 - FINISH
01:38:42.172 9 - START
01:38:42.173 3 - FINISH
01:38:42.173 1 - FINISH
01:38:42.173 2 - FINISH
01:38:42.173 10 - START
01:38:42.173 11 - START
01:38:42.173 12 - START
01:38:43.029 13 - START
01:38:43.030 4 - FINISH
01:38:43.030 14 - START
01:38:44.030 5 - FINISH
01:38:44.030 15 - START
01:38:44.030 16 - START
01:38:45.029 17 - START
01:38:45.031 6 - FINISH
有没有办法提高线程池增长的速度?
更新1。 上面的例子显示了主要问题:任务是由使用async / await样式代码的新现代库创建的。但是大多数任务都是具有线程阻塞操作的旧遗留代码。该应用程序工作。在恒定的低或恒定高负载下,它表现出良好的性能。当任务数量快速增加时,性能问题就开始了:虽然有数千个等待任务,但CPU利用率仍然很低。
应对上述情况的最简单方法是什么?
答案 0 :(得分:0)
线程池不知道任务使用async / await样式代码或线程阻塞代码。 因此,它无法改变其线程管理策略。
如果你有很多旧式的遗留线程阻塞代码,那么只需增加线程池中的最小线程数。