Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 05.03.20 23:36
Оценка:
Чего й то не понял:

    class Program
    {
        static async Task Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                var copy = i;

                _ = Task.Run(() =>
                {
                    Console.WriteLine("Start " + copy);
                    Thread.Sleep(5000);
                    Console.WriteLine("End " + copy);
                });
            }

            Console.ReadLine();
            Console.WriteLine("Hello World!");
        }
    }


Одновременно запускается не так много задач — как я понял, по числу ядер процессора или типа того (на моем старичке — только 4 штуки). Где это установлено? В TaskScheduler.Current.MaximumConcurrencyLevel — офердофигища.
Отредактировано 05.03.2020 23:38 Shmj . Предыдущая версия .
Re: Task.Run - кол-во одновременных по умолчанию
От: fmiracle  
Дата: 06.03.20 05:45
Оценка: 3 (1)
Здравствуйте, Shmj, Вы писали:

S>Одновременно запускается не так много задач — как я понял, по числу ядер процессора или типа того (на моем старичке — только 4 штуки). Где это установлено? В TaskScheduler.Current.MaximumConcurrencyLevel — офердофигища.


Таски тут ни при чем.

Task.Run использует для выполнения задач ThreadPool. ThreadPool, в свою очередь — это класс, который позволяет переиспользовать потоки, потому что создавать новый поток — довольно дорого.
Приложение у тебя свеженькое, в пул потоков не заполнен. Потому ThreadPool запускает обработки на нескольких потоках, остальные в очередь. И только позже, видя, что имеющихся потоков никак не хватает начинает (довольно неохотно) создавать новые.

Можешь доработать код, добавив в начало раскачку пула потоков:
for( int i = 0; i < 50; i++ )
            {
                var copy = i;
                ThreadPool.QueueUserWorkItem( ( state ) => {
                    Console.WriteLine( "init pool" );
                    Thread.Sleep( 3000 );
                } );
            }
            Thread.Sleep( 20000 );


а после — прошлый код и увидишь, что теперь в нем стало сразу стартовать куда больше задач.
Re: Есть целых два древних TaskScheduler-а
От: VladCore  
Дата: 06.03.20 07:07
Оценка:
Здравствуйте, Shmj, Вы писали:

Есть целых два древних TaskScheduler-а
Оба очень древние под древний дотнет:
int maxThreads = 2;
LimitedConcurrencyLevelTaskScheduler lcs = new LimitedConcurrencyLevelTaskScheduler(maxThreads);
QueuedTaskScheduler qs = new QueuedTaskScheduler(maxThreads);
TaskFactory factory = new TaskFactory(qs|lcs);

...
await factory.StartNew(() => ...);


QueuedTaskScheduler — этот с кучей плюшек но работает только на Windows, хотя и в .NET Core тоже. Но он и может юзать свой массив потоков и делегировать исполнение тасков заданному TaskScheduler-у.

LimitedConcurrencyLevelTaskScheduler — этот везде работает, но юзает всегда ThreadPool.

Я юзал оба. Хотя и сейчас юзаю.

На github очень много форков. Вот один из самых популярных: https://www.nuget.org/packages/ParallelExtensionsExtras/

S>Чего й то не понял:


S>
S>    class Program
S>    {
S>        static async Task Main(string[] args)
S>        {
S>            for (int i = 0; i < 100; i++)
S>            {
S>                var copy = i;

S>                _ = Task.Run(() =>
S>                {
S>                    Console.WriteLine("Start " + copy);
S>                    Thread.Sleep(5000);
S>                    Console.WriteLine("End " + copy);
S>                });
S>            }

S>            Console.ReadLine();
S>            Console.WriteLine("Hello World!");
S>        }
S>    }
S>


S>Одновременно запускается не так много задач — как я понял, по числу ядер процессора или типа того (на моем старичке — только 4 штуки). Где это установлено? В TaskScheduler.Current.MaximumConcurrencyLevel — офердофигища.
Отредактировано 06.03.2020 7:39 VladCore . Предыдущая версия . Еще …
Отредактировано 06.03.2020 7:16 VladCore . Предыдущая версия .
Re: Task.Run - кол-во одновременных по умолчанию
От: Danchik Украина  
Дата: 06.03.20 07:17
Оценка: +4
Здравствуйте, Shmj, Вы писали:

S>Чего й то не понял:


Ты очень не понял, если в код таски впаял Thread.Sleep(5000)
Таски как раз и придуманы чтобы переиспользовать потоки, а ты их блоканул.
Для этого дела есть
await Task.Delay(5000)
Re[2]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 06.03.20 07:46
Оценка: +1
Здравствуйте, fmiracle, Вы писали:

F>Task.Run использует для выполнения задач ThreadPool. ThreadPool, в свою очередь — это класс, который позволяет переиспользовать потоки, потому что создавать новый поток — довольно дорого.


Да, задать можно в ThreadPool.SetMinThreads(100, 1);

Может и дорого, но данный код выполняется быстрее во много крат, если одновременно стартануть все 100 потоков (т.к. большую часть времени просто ждет).
Re[3]: Task.Run - кол-во одновременных по умолчанию
От: fmiracle  
Дата: 06.03.20 08:42
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Может и дорого, но данный код выполняется быстрее во много крат, если одновременно стартануть все 100 потоков (т.к. большую часть времени просто ждет).


Оптимизация тредпула не предназначена для таких задач. Для подобных задач (долгие ожидания) хороши как раз await-able таски.
Re: Task.Run - кол-во одновременных по умолчанию
От: alexzzzz  
Дата: 06.03.20 14:44
Оценка: 6 (1) +1
Здравствуйте, Shmj, Вы писали:

S>Одновременно запускается не так много задач — как я понял, по числу ядер процессора или типа того (на моем старичке — только 4 штуки). Где это установлено? В TaskScheduler.Current.MaximumConcurrencyLevel — офердофигища.


Поскольку таски долгоживущие, запускай их соответственно:
var task = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Start " + copy);
        Thread.Sleep(5000);
        Console.WriteLine("End " + copy);
    },
    TaskCreationOptions.LongRunning
);
Re[3]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 07.03.20 07:04
Оценка: -1
Здравствуйте, Shmj, Вы писали:

S>Может и дорого, но данный код выполняется быстрее во много крат


Ускорение Thread.Sleep — великое твое достижение, да.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[4]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 07.03.20 12:25
Оценка: :)
Здравствуйте, Ночной Смотрящий, Вы писали:

S>>Может и дорого, но данный код выполняется быстрее во много крат

НС>Ускорение Thread.Sleep — великое твое достижение, да.

Вопрос не этом.
Re[5]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 07.03.20 17:51
Оценка:
Здравствуйте, Shmj, Вы писали:

НС>>Ускорение Thread.Sleep — великое твое достижение, да.

S>Вопрос не этом.

Вопрос именно в этом. Ты сперва блокируешь потоки, а потом прям открытие делаешь, что если блокированные потоки размножить, то работать начинает быстрее.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[6]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 07.03.20 20:57
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Вопрос именно в этом. Ты сперва блокируешь потоки, а потом прям открытие делаешь, что если блокированные потоки размножить, то работать начинает быстрее.


Вопрос был: "Где это установлено?"
Re: Task.Run - кол-во одновременных по умолчанию
От: GlebZ Россия  
Дата: 07.03.20 21:36
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Одновременно запускается не так много задач — как я понял, по числу ядер процессора или типа того (на моем старичке — только 4 штуки). Где это установлено? В TaskScheduler.Current.MaximumConcurrencyLevel — офердофигища.

Значение зависит от состояния виртуальной памяти и количества ядер. Основная проблема открытия потока — это то что он минимум занимает виртуальную память под стек(насколько я помню — 2 мега). Для того чтобы программа не была подвержена DDos атакам, и всяким глупостям программистов создающим кратковременные пиковые нагрузки, сделано что новый поток открывается в ThreadPool только с некоторой задержкой, в надежде что освободится уже выполненный поток. SetMinThreads поможет, если задача реально должна потреблять столько потоков (задач).
Re[7]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 07.03.20 21:39
Оценка:
Здравствуйте, Shmj, Вы писали:

НС>>Вопрос именно в этом. Ты сперва блокируешь потоки, а потом прям открытие делаешь, что если блокированные потоки размножить, то работать начинает быстрее.

S>Вопрос был: "Где это установлено?"

Тебе сразу же сказали про ThreadPool. Но я то не на то сообщение отвечал, а на вот это прекрасное заявление:

Может и дорого, но данный код выполняется быстрее во много крат, если одновременно стартануть все 100 потоков (т.к. большую часть времени просто ждет).


Т.е. ты заведомо кривой код вылечил кривым костылем, о чем я тебе и намекнул.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[8]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 07.03.20 23:03
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>

НС>Может и дорого, но данный код выполняется быстрее во много крат, если одновременно стартануть все 100 потоков (т.к. большую часть времени просто ждет).


НС>Т.е. ты заведомо кривой код вылечил кривым костылем, о чем я тебе и намекнул.


Так, давай разберемся что ты хочешь донести. Что значит "кривой код"?

Да, потоки блокируем с помощью Sleep. И что? Ты вообще принципиально против блокировок потоков? Напиши свой вариант без блокировки потоков в теме: http://rsdn.org/forum/dotnet/7674190.flat
Автор: Shmj
Дата: 06.03.20
— обкашляем.
Re[9]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 07.03.20 23:08
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Так, давай разберемся что ты хочешь донести. Что значит "кривой код"?


Ты точно программист?

S>Да, потоки блокируем с помощью Sleep. И что?


И то что это в подавляющем большинстве ситуаций плохо.

S> Ты вообще принципиально против блокировок потоков?


В сценариях когда тебе требуются сотни потоков — да, против.

S> Напиши свой вариант без блокировки потоков в теме: http://rsdn.org/forum/dotnet/7674190.flat
Автор: Shmj
Дата: 06.03.20
— обкашляем.


Как я тебе напишу без блокировки, если у тебя там тоже одни слипы? Запрос к серверу обычно можно делать через IOCP.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[10]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 07.03.20 23:49
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

S>>Так, давай разберемся что ты хочешь донести. Что значит "кривой код"?

НС>Ты точно программист?

Моя личность не имеет отношения к делу.

НС>И то что это в подавляющем большинстве ситуаций плохо.


Кстати, а за счет чего достигается задержка с помощью Task.Delay? Чего-то не смотрел внутренности.

>Как я тебе напишу без блокировки, если у тебя там тоже одни слипы? Запрос к серверу обычно можно делать через IOCP.


Ну, там где запрос к серверу — можно и оставить блокировку, она не на долго. А вот где ожидание — Task.Delay.
Re[11]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 08.03.20 00:03
Оценка:
Здравствуйте, Shmj, Вы писали:

S>>>Так, давай разберемся что ты хочешь донести. Что значит "кривой код"?

НС>>Ты точно программист?
S>Моя личность не имеет отношения к делу.

Зато имеют задаваемые тобой вопросы. Ты меня еще спроси что такое код.

НС>>И то что это в подавляющем большинстве ситуаций плохо.

S>Кстати, а за счет чего достигается задержка с помощью Task.Delay? Чего-то не смотрел внутренности.

Ну так посмотри. Таймер там.

>>Как я тебе напишу без блокировки, если у тебя там тоже одни слипы? Запрос к серверу обычно можно делать через IOCP.

S>Ну, там где запрос к серверу — можно и оставить блокировку, она не на долго. А вот где ожидание — Task.Delay.

Ну так вперед. Заменить свои слипы и посмотреть что вышло — быстрее чем это сообщение писать.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[12]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 08.03.20 00:39
Оценка: -1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>>>И то что это в подавляющем большинстве ситуаций плохо.

S>>Кстати, а за счет чего достигается задержка с помощью Task.Delay? Чего-то не смотрел внутренности.

НС>Ну так посмотри. Таймер там.


А таймер насколько менее ресурсоемок, нежели создание потока?
Re[13]: Task.Run - кол-во одновременных по умолчанию
От: Ночной Смотрящий Россия  
Дата: 08.03.20 00:50
Оценка:
Здравствуйте, Shmj, Вы писали:

НС>>Ну так посмотри. Таймер там.

S>А таймер насколько менее ресурсоемок, нежели создание потока?

Блин, да напиши уже код.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[14]: Task.Run - кол-во одновременных по умолчанию
От: Shmj Ниоткуда  
Дата: 08.03.20 09:47
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Блин, да напиши уже код.


Проверил. 1000 блокированных потоков отжирают около +25 МБ ОЗУ. На самом деле не критично — копейки. Но ради чистоты идеи — да, лучше заюзать таймеры.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.