代码:
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在做什么吗?有人能澄清一下发生了什么事吗?
发布于 2011-09-13 05:06:45
为什么它可以立即很好地启动前3个任务,但是任务4开始需要5-10秒,任务4开始后,任务5开始需要5-10秒,以此类推。是GC在做什么吗?有人能澄清一下发生了什么事吗?
默认情况下,第一次运行时,将使用最小数量的工作线程来分配ThreadPool。在调度完前4个任务后,线程池将随着时间的推移“加速”以处理更多任务,这就是您看到延迟的原因。
在我的系统(有8个内核)上,前8个是瞬时的,然后下两个会在一秒后启动。
在您的示例中,如果您运行测试两次,即second时间,那么所有线程都将立即启动。这是因为,在第一次运行之后,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();
}请注意,这个行为实际上与第三方公共关系不大--它更多的是使用默认的TaskScheduler,它只是将任务传递给ThreadPool。例如,如果在StartNew()调用中使用LongRunning提示设置这些线程,它们都会立即启动(因为默认调度程序将设置一个新的专用线程并立即执行它)。
发布于 2011-09-13 05:04:20
TPL包含非常复杂的算法,可以适应工作负载。您正在经历的事情听起来很适合4核计算机-- TPL已经决定做一些它认为在创建了这么多线程的情况下是有益的事情。
https://stackoverflow.com/questions/7393938
复制相似问题