为什么Thread和Task之间的性能差异如此之大?

时间:2012-10-29 15:54:31

标签: c# multithreading

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秒
这怎么可能?为什么这么大的差异?

6 个答案:

答案 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稍后可以启动它(取决于可用线程/任务的数量)。

MSDN说,在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