Будет Параллельно.Процесс ForEach для того, чтобы MaxDegreeOfParallelism=1?

и Parallel.ForEach() с MaxDegreeOfParallelism==1 гарантированно обрабатывать входные данные в порядке перечисления?

Если ответ "нет", есть ли способ, чтобы реализовать такое поведение?

2 ответов


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

Параллельный.Метод ForEach не гарантирует порядок выполнения. В отличие от последовательного цикла ForEach, входящие значения не всегда обрабатываются по порядку.

лучше использовать Parallel.ForEach как публичный API разработан:для обработки элементов в параллельный образ. Если вам нужно обрабатывать элементы последовательно, вам намного лучше использовать обычный foreach петли. Намерение яснее, чем использование MaxDegreeOfParallelism = 1.

С учетом сказанного, ради любопытства, я взглянул на исходный код для .NET 4.7.1. Короткий ответ: да, элементы будут обрабатываться последовательно, если MaxDegreeOfParallelism = 1. Однако, вы не должны полагаться на это для будущих реализаций, потому что это может не всегда быть путь.

  1. посмотреть Parallel.ForEach и следуя ему, вы в конечном итоге увидите, что коллекция, которую нужно перебрать, разделена (этот процесс немного отличается от того, является ли это TSource[], List<TSource> или IEnumerable<TSource>.

  2. Task.SavedStateForNextReplica и Task.SavedStateFromPreviousReplica переопределяются в ParallelForReplicaTask для связи состояния между задачами, выполняемыми параллельно. В этом случае они используются для связи раздела задачи следует повторить.

  3. наконец, давайте посмотрим на Task.ExecuteSelfReplicating. ParallelForReplicatingTask переопределяет ShouldReplicate на основе степени параллелизма, указанной, а такжеMaximumConcurrencyLevel. Итак, это с MaxDegreeOfParallelism = 1 создаст только одну дочернюю задачу. Таким образом, эта задача будет работать только над одним созданным разделом.

Итак, чтобы ответить на ваш вопрос: Как писать, Parallel.ForEach с MaxDegreeOfParallism = 1 буду перечислять коллекция от начала до конца на TSource[], от начала до конца на IList<TSource> и использовать GetEnumerator на IEnumerable<TSource>, С немного разными путями в зависимости от того, если IEnumerable<TSource> можно бросить в OrderablePartitioner<TSource> или нет. Эти три пути в Parallel.ForEachWorker.

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

я надеюсь, что это может ответьте на свой вопрос, но очень важно помнить:не полагайтесь на это. Очень возможно, что эта реализация может измениться в будущем.


из MSDN:

Параллельный.Метод ForEach не гарантирует порядок выполнения. В отличие от последовательного цикла ForEach, входящие значения не всегда обрабатываются по порядку.

https://msdn.microsoft.com/library/ff963552.aspx