Windows 7,Intel CORE i3,64位,RAM 4Gb,2.27 GHz
.NET Framework 4.0
我有以下代码:
static void Main(string[] args)
{
var timer = new Stopwatch();
timer.Start();
for (int i = 0; i < 0xFFF; ++i)
{
// I use one of the following line at time
Task.Factory.StartNew(() => { });
new Thread(() => { }).Start();
}
timer.Stop();
Console.WriteLine(timer.Elapsed.TotalSeconds);
Console.ReadLine();
}
如果我使用Task,输出总是小于 0.01秒,但如果我使用Thread,输出总是大于 40秒!
这怎么可能?为什么这么大的差异?
答案 0 :(得分:34)
两者不一样。
使用Task.Factory.StartNew
时,您计划在ThreadPool
上运行任务。当你创建一个新的Thread
时,你必须创建并开始一个新的线程。
在第一种情况下,线程已经创建并且重用。这导致调度任务的开销要低得多,因为不必每次迭代都创建线程。
但请注意,行为并不相同。创建单独的线程时,每个任务都会获得自己的线程。他们都会马上开始。使用Task.Factory.StartNew
时,它们会被放入调度程序以在ThreadPool
上运行,这将(可能)限制启动的并发线程数。这通常是一件好事,因为它可以防止过度发生。
答案 1 :(得分:4)
每次启动Task
时,它都会进入一个由多个线程提供服务的池中,其中许多线程可能是预先创建的。任务与池中的线程的比率为M:N
。
每次启动Thread
时,它都会创建一个新线程以及与线程创建相关的所有开销。由于您是显式创建线程,因此线程比率为1:1。
任务与线程的比率越接近1,它将采取“更慢”的任务启动。实际上,ThreadPool
确保比率远远高于1.
答案 2 :(得分:1)
您的测试存在问题,因为您不必等待每个线程/任务完成。
任务使用队列,因此创建任务比创建线程要快得多。
我敢打赌,即使您等待任务/主题完成,使用任务也会更快。创建然后销毁线程的开销很高。这就是创建Task.Factory的原因!
答案 3 :(得分:0)
Task.Factory.StartNew()
不会立即启动任务,只是计划它,以便TaskScheduled稍后可以启动它(取决于可用线程/任务的数量)。
Thread.Start()
操作系统可以安排执行后,与OS的交互比使用.NET Framework的TaskScheduler要慢得多,但在这种程度上却没有。
回到你的例子,0xFFF == 4095,所以你要安排4095个线程,这需要40秒。一秒钟内102个线程是一个非常好的时机! :)
答案 4 :(得分:0)
调用Task.Factory.StartNew
并不一定会创建新线程,它们由TaskScheduler
根据运行代码的机器所拥有的核心数来管理。
如果您安排(通过调用Task.Factory.StartNew
)多个可以同时运行的任务,它们将排队并在更多资源可用时运行。
答案 5 :(得分:0)
创建新线程的速度很慢,但速度并不慢。 尼克报道〜10ms /线程。 最有可能的是它发生在Visual Studio调试器下。 我在Visual Studio调试器下每个新线程获得~3.9ms。 每个没有调试器的新线程我得到~0.15ms。
http://dennisgorelik.livejournal.com/125269.html?thread=2238805#t2238805