29

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

4

6 回答 6

37

两者不一样。

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

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

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

于 2012-10-29T15:56:37.277 回答
4

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

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

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

于 2012-10-29T15:57:06.780 回答
1

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

任务使用队列,因此创建任务比创建线程快得多。

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

于 2012-10-29T16:01:47.440 回答
0

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

MSDN 说,在Thread.Start()操作系统可以调度它执行后,与操作系统的交互比使用 .NET Framework 的 TaskScheduler 慢得多,但没有这样的程度。

回到您的示例,0xFFF == 4095,因此您正在调度 4095 个线程,这需要 40 秒。一秒102个线程是个不错的时机!:)

于 2012-10-29T15:56:56.310 回答
0

调用Task.Factory.StartNew不一定会创建一个新线程,它们是由TaskScheduler运行代码的机器有多少内核等来管理的。

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

于 2012-10-29T15:58:45.243 回答
0

创建新线程很慢,但没那么慢。尼克报告约 10 毫秒/线程。很可能它发生在 Visual Studio 调试器下。在 Visual Studio 调试器下,每个新线程我得到约 3.9 毫秒。在没有调试器的情况下,每个新线程我得到约 0.15 毫秒。

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

于 2017-02-06T20:10:49.150 回答