Будет Параллельно.Процесс ForEach для того, чтобы MaxDegreeOfParallelism=1?
и Parallel.ForEach()
с MaxDegreeOfParallelism==1
гарантированно обрабатывать входные данные в порядке перечисления?
Если ответ "нет", есть ли способ, чтобы реализовать такое поведение?
2 ответов
во-первых, правильно, что официальная документация Microsoft по параллельному программированию указано, что исполнение заказа не гарантируется.
Параллельный.Метод ForEach не гарантирует порядок выполнения. В отличие от последовательного цикла ForEach, входящие значения не всегда обрабатываются по порядку.
лучше использовать Parallel.ForEach
как публичный API разработан:для обработки элементов в параллельный образ. Если вам нужно обрабатывать элементы последовательно, вам намного лучше использовать обычный foreach
петли. Намерение яснее, чем использование MaxDegreeOfParallelism = 1
.
С учетом сказанного, ради любопытства, я взглянул на исходный код для .NET 4.7.1. Короткий ответ: да, элементы будут обрабатываться последовательно, если MaxDegreeOfParallelism = 1
. Однако, вы не должны полагаться на это для будущих реализаций, потому что это может не всегда быть путь.
посмотреть
Parallel.ForEach
и следуя ему, вы в конечном итоге увидите, что коллекция, которую нужно перебрать, разделена (этот процесс немного отличается от того, является ли этоTSource[]
,List<TSource>
илиIEnumerable<TSource>
.Task.SavedStateForNextReplica
иTask.SavedStateFromPreviousReplica
переопределяются вParallelForReplicaTask
для связи состояния между задачами, выполняемыми параллельно. В этом случае они используются для связи раздела задачи следует повторить.наконец, давайте посмотрим на
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, входящие значения не всегда обрабатываются по порядку.