Будет Параллельно.Процесс 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, входящие значения не всегда обрабатываются по порядку.