Можно ли определить параллелизм задач с помощью Task.Delay для форсирования нового потока? - PullRequest
0 голосов
/ 03 апреля 2020

Я пытаюсь определить, что Задачи МОГУТ выполняться параллельно в зависимости от решений, принятых планировщиком задач. Мне сказали, что это не является доказательством:

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var tasks = new List<Task>();
        for (int i = 0; i < 50; i++)
        {
            tasks.Add(Task.Run(async () =>
            {
                await Task.Delay(1000);
            }));
        }

        await Task.WhenAll(tasks);
        stopwatch.Stop();
        // should be 50000 without any parallelism
        var elapsedTime = stopwatch.ElapsedMilliseconds; // on my machine actual result is around 10000

Так что я сейчас очень смущен этим. Как могло быть возможно, что конечный результат выполнения времени меньше, чем время, необходимое для выполнения каждой задачи * количество задач, а не доказывает некоторую степень параллелизма?

Ответы [ 2 ]

4 голосов
/ 03 апреля 2020

Я пытаюсь определить, что Задачи МОГУТ выполняться параллельно в зависимости от решений, принятых планировщиком задач ... Как может быть так, что конечный результат в выполнении времени меньше, чем время, необходимое для выполнения каждого задача * количество задач и не доказать некоторую степень параллелизма?

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

Важно отметить, что планировщики задач применяются только к выполняющимся задачам, т. Е. Задачам, которые фактически выполняют код или заблокированы. Поток, который запускает await Task.Delay, не выполняет код и не блокируется во время задержки.

Так что я имею в виду, может ли Task.wall быть параллельным или только параллельным?

Вы можете - теоретически - использовать WhenAll параллельно. Вам просто нужно изменить код на блокирующий, а не асинхронный, и он будет работать параллельно:

var stopwatch = new Stopwatch();
stopwatch.Start();
var tasks = new List<Task>();
for (int i = 0; i < 50; i++)
{
  tasks.Add(Task.Run(async () =>
  {
    Thread.Sleep(1000);
  }));
}

await Task.WhenAll(tasks);
stopwatch.Stop();
var elapsedTime = stopwatch.ElapsedMilliseconds;

В этом случае ваш код работает параллельно. Использование Task.WhenAll, как это будет работать, но это необычно. Обычно параллельный код потребляется с использованием методов блокировки, таких как Task.WaitAll.

0 голосов
/ 03 апреля 2020

Вы не должны пытаться самостоятельно контролировать степень параллелизма.

Лучший способ, чем явное создание и запуск потоков, - использовать параллель для:

Parallel.For(0, 50, i => { Thread.Sleep(1000); } );

Задача Параллель Затем механизм автоматически определяет оптимальное количество потоков (на основе количества доступных ядер) и распределяет задачи между этими потоками.

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

...