@unknown3

Task vs ThreadPool vs new Thread?

Стоит задача, обработать 100+ долговременных операций ( допустим каждая занимает по 10 сек). Естественно обрабатывать нужно асинхронно, все одновременно. Ну 100 штук обработали и миллион еще на походе если что...
Так вот как сделать это более правильно и более быстро?
Ограничение: .NET Framework 4.0
Написал пример 3х реализаций
for (int i = 0; i < 100; i++) {
                int j = i;
                Task t = new Task(() => {
                    Console.WriteLine("RUN "+j);
                    Thread.Sleep(10000);
                    Console.WriteLine("end " + j);
                });
                t.Start();

                //ИЛИ
                ThreadPool.QueueUserWorkItem(state => {
                    Console.WriteLine("RUN " + j);
                    Thread.Sleep(10000);
                    Console.WriteLine("end " + j);
                });
                //ИЛИ
                Thread t = new Thread(() =>
                {
                    Console.WriteLine("RUN " + j);
                    Thread.Sleep(10000);
                    Console.WriteLine("end " + j);
                });
                t.Start();
            }

Если использовать Task и ThreadPool, то уже на 20й таске все резко замедляется и идет очень медленно, создание каждой новой таски или тредпула 1-3 сек ( даже если указали что ThreadPool.SetMaxThreads(100, 100);)
Если использовать new Thread, то всё работает как нужно. Мгновенно всё создается и выполняется одновременно и завершается +- одновременно.
НО! Как везде утверждают что таски и тредпулы быстрее, лучше использовать их. Что new thread это долгая и дорогостоящая операция, но тест показывает что всё как раз на оборот.
Так какой способ вы бы использовали?
  • Вопрос задан
  • 653 просмотра
Решения вопроса 1
sarapinit
@sarapinit Куратор тега C#
Точу водой камень
1) Смотрите, если у вас асинхронная работа (вы пишете работа с сокетами), то создавать много потоков, нецелесообразно, так как за потоком подразумевается работа процессора, а при работе с сокетами, этот поток будет большую часть времени простаивать.

2) Таски используют пул потоков, поэтому особой разницы между ThreadPool.QueueUserWorkItem и запуском Таски нет.

3) Что Thread.Sleep(10000) что Task.Delay(10000).Wait() - это блокирующая операция, которая приводит к тому что называют thread pool starvation. То есть поток не имеет возможности вернуться в пул и переиспользоваться. У пула потоков есть задержка на ввод нового потока в работу, поэтому у вас все и тормозит.

Вывод в том, что вы некорректно готовите асинхронность. Во всех случаях вы блокируете потоки и количество потоков у вас во всех случаях примерно одинаковое задействуется. Если вы ограничены 4.0, то скорее всего, лучшим вариантом будет старая модель асинхронности .net
https://docs.microsoft.com/en-us/dotnet/standard/a...
У сокетов есть соответствующие методы
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы