Parallel.For цикл завершается слишком рано - PullRequest
0 голосов
/ 28 февраля 2019

Я пытаюсь добавить все задачи в список параллельно, а затем ожидаю их выполнения.Код для этого:

List<Task<bool>> tasks = new List<Task<bool>>();                

Parallel.For(0, 500, file =>
{
  tasks.Add(SomeTask());
});

Console.WriteLine("Total tasks = " + tasks.Count);

Когда я выполняю следующий код, иногда я получаю размер списка задач (tasks.Count) как 493 или 500 или 498. Но это не является детерминированным.Что мне делать?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Методы, возвращающие задачи (например, SomeTask), обычно возвращаются очень быстро, и распараллеливание их вызовов обычно приводит к более медленному выполнению.

Для коллекций задач гораздо более нормальнобыть построенным с (не параллельным) LINQ:

var tasks = Enumerable.Range(0, 500).Select(file => SomeTask()).ToList();
Console.WriteLine("Total tasks = " + tasks.Count);

Если ваш метод возврата задачи имеет некоторый код, связанный с процессором, и вам do необходимо выполнитьSomeTask в потоке пула потоков, тогда вы можете использовать параллелизм.Один простой подход - заключить вызов в Task.Run:

var tasks = Enumerable.Range(0, 500).Select(file => Task.Run(() => SomeTask())).ToList();
Console.WriteLine("Total tasks = " + tasks.Count);
0 голосов
/ 28 февраля 2019

У вас есть то, что называется состояние гонки .Вы получаете доступ к списку из нескольких потоков без синхронизации, из-за чего он находится в странном состоянии.

Вместо этого вы можете использовать потокобезопасный объект, такой как ConcurrentStack (или ConcurrentBag или ConcurrentQueue, в зависимости от того, что выделать с коллекцией):

ConcurrentStack<Task<bool>> tasks = new ConcurrentStack<Task<bool>>();                

Parallel.For(0, 500, file =>
{
  tasks.Push(SomeTask());
});

Console.WriteLine("Total tasks = " + tasks.Count);
...