Подтвердить что ты не робот

Почему такая разница в производительности между Thread и Task?

Windows 7, Intel CORE i3, 64 бит, оперативная память 4 ГБ, 2,27 ГГц
.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 секунд!
Как это возможно? Почему так много разницы?

4b9b3361

Ответ 1

Оба не совпадают.

Когда вы используете Task.Factory.StartNew, вы планируете выполнение задачи на ThreadPool. Когда вы создаете новый Thread, вам нужно создать и запустить новый поток.

В первом случае потоки уже созданы и повторно используются. Это приводит к тому, что накладные расходы на планирование задач намного ниже, так как нити не должны создаваться каждой итерацией.

Обратите внимание, что поведение не одно и то же. При создании отдельного потока каждая задача получает собственный поток. Они сразу начнут работать. При использовании Task.Factory.StartNew они помещаются в планировщик для запуска в ThreadPool, который (потенциально) ограничивает количество запущенных параллельных потоков. Это, как правило, хорошо, поскольку это предотвращает чрезмерное возникновение.

Ответ 2

Каждый раз, когда вы запускаете Task, он переходит в пул, который должен обслуживаться несколькими потоками, многие из которых могут быть предварительно созданы. В пуле есть отношение M:N задач к потокам.

Каждый раз, когда вы запускаете Thread, он создает новый поток и все служебные данные, связанные с созданием потоков. Поскольку вы явно создаете поток, существует соотношение потоков 1:1.

Чем ближе отношение задач к потокам достигает 1, тем медленнее запускается задача. В действительности, ThreadPool обеспечивает, чтобы соотношение оставалось намного выше 1.

Ответ 3

Task.Factory.StartNew() не запускает задачу сразу, она просто планирует ее, поэтому TaskScheduled сможет запустить ее чуть позже (зависит от количества доступных потоков/задач).

MSDN заявляет, что после Thread.Start() операционная система может запланировать ее выполнение, взаимодействие с ОС намного медленнее, чем с .NET Framework TaskScheduler, но не в такой степени.

И вернемся к вашему примеру, 0xFFF == 4095, поэтому вы планируете 4095 потоков, и это занимает 40 секунд. 102 нити в секунду - довольно неплохое время!:)

Ответ 4

Вызов Task.Factory.StartNew не обязательно создает новый поток, они управляются с помощью TaskScheduler на основе количества ядер и т.д. на компьютере работает код.

Если вы планируете (вызывая Task.Factory.StartNew) больше задач, чем могут быть одновременно запущены, они будут поставлены в очередь и запущены по мере поступления большего количества ресурсов.

Ответ 5

У вас есть проблема с вашим тестом, поскольку вы не ждете завершения каждого потока/задачи.

Задача использует очередь, поэтому ее гораздо быстрее создать задачу, чем поток.

Готов поспорить, что даже если вы ждали завершения задач/потоков, то использование задачи выполняется быстрее. Накладные расходы на создание и уничтожение Thread очень высоки. Вот почему была создана Task.Factory!

Ответ 6

Создание новых потоков происходит медленно, но не так медленно. Ник сообщил ~ 10 мс/нить. Скорее всего, это произошло в отладчике Visual Studio. Я получаю ~ 3.9ms за новый поток в отладчике Visual Studio. Я получаю ~ 0.15ms за новый поток без отладчика.

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