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

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  { }); new Thread(() => { }).Start(); } timer.Stop(); Console.WriteLine(timer.Elapsed.TotalSeconds); Console.ReadLine(); } 

如果我使用Task,输出总是小于0.01秒 ,但如果我使用Thread,输出总是大于40秒
这怎么可能? 为什么这么大的差异?

两者不一样。

当您使用Task.Factory.StartNew ,您正在安排在ThreadPool上运行的任务。 当你创建一个新Thread ,你必须创建并启动一个新线程。

在第一种情况下,线程已经创建并重用 。 这导致调度任务的开销要低得多,因为不必每次迭代都创建线程。

但请注意,行为并不相同。 创建单独的线程时,每个任务都会获得自己的线程。 他们都会马上开始。 当使用Task.Factory.StartNew ,它们被放入调度程序以在ThreadPool上运行,这将(可能)限制启动的并发线程数。 这通常是一件好事,因为它可以防止发生过度推翻。

每次启动Task它都会进入一个池中,由多个线程提供服务,其中许multithreading可能是预先创建的。 任务与池中的线程之间存在M:N比率。

每次启动Thread它都会创建一个新线程以及与线程创建相关的所有开销。 由于您明确创建了一个线程,因此线程比例为1:1。

任务与线程的比率越接近1,它将采取“更慢”的任务启动。 实际上, ThreadPool确保比率保持远高于1。

您的测试存在问题,因为您不必等待每个线程/任务完成。

Task使用队列,因此创建Task比使用Thread要快得多。

我敢打赌,即使你等待任务/线程完成,使用任务更快。 创建然后销毁线程的开销很高。 这就是Task.Factory创建的原因!

调用Task.Factory.StartNew不一定会创建新线程,它们由TaskScheduler根据运行代码的机器所拥有的核心数来管理。

如果您安排(通过调用Task.Factory.StartNew )可以同时运行的任务,那么它们将排队并在更多资源可用时运行。

Task.Factory.StartNew()不会立即启动任务,只是调度它,以便TaskScheduled稍后可以启动它(取决于可用线程/任务的数量)。

MSDN说在Thread.Start()操作系统可以将其安排执行之后,与OS的交互比使用.NET Framework的TaskScheduler要慢得多,但在这种程度上却没有。

回到你的例子,0xFFF == 4095,所以你安排了4095个线程,这需要40秒。 一秒钟内102个线程是一个非常好的时机! 🙂

创建新线程的速度很慢,但速度并不慢。 尼克报道〜约10毫秒/线程。 最有可能的是它发生在Visual Studio调试器下。 我在Visual Studio调试器下每个新线程获得~3.9ms。 每个没有调试器的新线程我得到~0.15ms。

http://dennisgorelik.livejournal.com/125269.html?thread=2238805#t2238805