C# 为什么线程和任务之间的性能差异如此之大?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13125105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:40:23  来源:igfitidea点击:

Why so much difference in performance between Thread and Task?

c#multithreading

提问by Nick

Windows 7, Intel CORE i3, 64 bit, RAM 4Gb, 2.27 GHz
.NET Framework 4.0

Windows 7,英特尔酷睿 i3,64 位,RAM 4Gb,2.27 GHz
.NET Framework 4.0

I have the following code:

我有以下代码:

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();
}

If I use Task the output is always less then 0.01 seconds, but if I use Thread the output is always greater than 40 seconds!
How is it possible? Why so much difference?

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

采纳答案by Reed Copsey

The two are not the same.

两者并不相同。

When you use Task.Factory.StartNew, you're scheduling a task to run on the ThreadPool. When you make a new Thread, you're having to create and start a new thread.

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

In the first case, the threads are already created and reused. This causes the overhead of scheduling the tasks to be far lower, as the threads don't have to be created each iteration.

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

Note that the behavior is not the same, however. When creating a separate thread, each task is getting it's own thread. They will all get started right away. When using Task.Factory.StartNew, they're put into the scheduler to run on the ThreadPool, which will (potentially) limit the number of concurrent threads started. This is usually a good thing, as it prevents overthreading from occurring.

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

回答by sll

Task.Factory.StartNew()does not start a task immediately it just schedules it so a TaskScheduled would be able starting it a bit later (depends on number of available threads/tasks).

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

MSDN saying that after Thread.Start()operating system can schedule it for execution, interactions with OS is much slower than with .NET Framework's TaskScheduler but not in such degree.

MSDN 说Thread.Start()操作系统可以调度它执行后,与操作系统的交互比与 .NET Framework 的 TaskScheduler 慢得多,但不是这个程度。

And back to your example, 0xFFF == 4095, so you are scheduling 4095 threads and this takes 40 seconds. 102 threads in a second is a pretty good timing! :)

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

回答by user7116

Every time you start a Taskit goes into a pool to be served by a number of threads, many of which may be pre-created. There is an M:Nratio of tasks to threads in the pool.

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

Every time you start a Threadit creates a new thread and all of the overhead associated with thread creation. Since you are explicitly creating a thread, there is a 1:1 ratio of threads.

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

The closer the ratio of tasks to threads reaches 1, the "slower" task startup it will take. In reality, the ThreadPoolensures the ratio stays much higher than 1.

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

回答by Trevor Pilley

Calling Task.Factory.StartNewdoesn't necessarily create a new thread, they are managed by the TaskSchedulerbased upon how many cores etc the machine has that is running the code.

调用Task.Factory.StartNew不一定会创建新线程,它们由TaskScheduler基于运行代码的机器拥有的内核数量等进行管理。

If you schedule (by calling Task.Factory.StartNew) more tasks than can be concurrently run, they will be queued and run as more resources become available.

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

回答by Richard Schneider

You have an issue with your test, in that you don't wait for each Thread/Task to finish.

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

Task uses a queue, so its much faster to create a Task than a Thread.

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

I'll bet that even if you waited for Tasks/Threads to finish, that using a Task is faster. The overhead of creating and then destroying a Thread is high. That's why the Task.Factory was created!

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

回答by Dennis Gorelik

Creating new threads is slow, but not that slow. Nick reported ~10ms/thread. Most likely it happened under Visual Studio debugger. I am getting ~3.9ms per new thread under Visual Studio debugger. I am getting ~0.15ms per new thread without debugger.

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

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

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