多个任务变慢

代码:

static void DoIt(string name) { Console.WriteLine("Hello {0} | {1}", name, Thread.CurrentThread.ManagedThreadID); Thread.Sleep(5000); Console.WriteLine("Bye {0} | {1}", name, Thread.CurrentThread.ManagedThreadID); } static void Main() { Task.Factory.StartNew(() => DoIt("One")); Task.Factory.StartNew(() => DoIt("Two")); Task.Factory.StartNew(() => DoIt("Three")); Task.Factory.StartNew(() => DoIt("Four")); Task.Factory.StartNew(() => DoIt("Five")); Task.Factory.StartNew(() => DoIt("Six")); Task.Factory.StartNew(() => DoIt("Seven")); Task.Factory.StartNew(() => DoIt("Eight")); Task.Factory.StartNew(() => DoIt("Nine")); Task.Factory.StartNew(() => DoIt("Ten")); Console.ReadKey(); } 

为什么它可以立即精确启动前3个任务,但是任务4启动需要5-10秒,任务4启动后,任务5启动前需要5-10秒,依此类推。 GC是做什么的吗? 有人可以澄清发生了什么事吗?

为什么它可以立即精确启动前3个任务,但是任务4启动需要5-10秒,任务4启动后,任务5启动前需要5-10秒,依此类推。 GC是做什么的吗? 有人可以澄清发生了什么事吗?

默认情况下,第一次运行此时,将使用最小工作线程数分配ThreadPool 。 在安排了前4个任务之后,线程池将“加速”以便随着时间的推移处理更多,这就是您看到延迟的原因。

在我的系统(有8个核心)上,前8个是即时的,然后接下来的两个在一秒后启动。

在您的情况下,如果您第二次运行测试,则线程将立即启动。 这是因为,在第一次运行之后,ThreadPool应该有足够的工作人员立即安排它。

请尝试以下操作以查看此行为。 如果您保留SetMinThreads呼叫,这些都将立即安排。 如果你注释掉它,你会看到,第一次,它需要一段时间,但第二次(如果你等待线程完成),线程将立即运行。

 static void DoIt(string name) { Console.WriteLine("Hello {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now); Thread.Sleep(5000); Console.WriteLine("Bye {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now); } static void Main() { int workerThreads, complete; ThreadPool.GetMinThreads(out workerThreads, out complete); Console.WriteLine(workerThreads); // Comment out this line to see the difference... // WIth this commented out, the second iteration will be immediate ThreadPool.SetMinThreads(100, complete); Action run = () => { for (int i = 0; i < 20; ++i) { int tmp = i; Task.Factory.StartNew(() => DoIt(tmp.ToString())); } }; run(); Console.WriteLine("Press a key to run again..."); Console.ReadKey(); run(); Console.WriteLine("Press a key to exit..."); Console.ReadKey(); } 

请注意,这种行为实际上与整个TPL没什么关系 – 它更像是默认的TaskScheduler ,它只是将任务传递给ThreadPool 。 例如,如果要在StartNew()调用中使用LongRunning提示设置这些线程,则它们都会立即启动(因为默认调度程序将设置一个新的专用线程并立即执行它)。

任务没有减慢,它们被任务并行库排队。 CLR知道您的计算机上有多少逻辑核心可用; TPL线程池使用此信息来确定要提供的工作线程数。 在您的情况下,您可能有四个逻辑核心; 为主线程(正在运行Main()取一个,三个核心(和三个线程池工作者)仍然执行任务。

TPL包含非常复杂的算法,可以适应工作负载。 您正在体验4核机器的声音 – TPL决定在创建如此multithreading的情况下做一些它认为有益的事情。