Параллельное .For и Break() непонимание?

Я изучаю цикл Parallelism Break in a.

После чтения this и this Я все еще есть вопрос:

Я ожидаю этот код:

 Parallel.For(0, 10, (i,state) =>  
     { 
                Console.WriteLine(i); if (i == 5) state.Break(); 
     }

Чтобы получить не более 6 чисел (0..6). не только он этого не делает, но имеет другую длину результата:

02351486
013542
0135642

Очень раздражает. (где ад здесь Break() {после 5} здесь?)

Итак, я посмотрел на msdn

Разрыв может использоваться для связи с циклом, чтобы никакие другие итерации после текущей итерации не выполнялись. Если Break вызывается из 100-й итерации цикла for, итерации в параллельно от 0 до 1000, все итерации менее 100 должны но итерации от 101 до 1000 не нужны.

Quesion #1 :

Какие итерации? общий счетчик итераций? или на поток? Я уверен, что это за поток. пожалуйста, одобрите.

Question #2 :

Предположим, что мы используем раздел Parallel + range (из-за отсутствия изменения стоимости процессора между элементами), поэтому он делит данные между потоками. Итак, если у нас есть 4 ядра (и совершенные деления между ними):

core #1 got 0..250
core #2 got 251..500
core #3 got 501..750
core #4 got 751..1000

поэтому поток в core #1 встретится value=100 когда-нибудь и сломается. это будет его номер итерации 100. Но поток в core #4 получил больше квантов, и теперь он находится на 900. он выходит за пределы своей итерации 100'th. У него нет индекса меньше 100, чтобы его остановить! - , поэтому он покажет им все.

Я прав? вот почему я получаю более 5 элементов в моем примере?

Question #3 :

Как cn я действительно ломаюсь, когда (i == 5)?

p.s.

Я имею в виду, давай! когда я делаю Break(), я хочу, чтобы цикл был остановлен. как и в обычном цикле For.

Ответ 1

Чтобы получить не более 6 чисел (0..6).

Проблема состоит в том, что это не даст не более 6 чисел.

Что происходит, когда вы нажимаете на цикл с индексом 5, вы отправляете запрос "break". Break() приведет к тому, что цикл больше не обрабатывает значения >5, а обрабатывает все значения <5.

Однако все значения, которые уже были начаты, будут обрабатываться. Поскольку различные индексы работают параллельно, они больше не заказываются, поэтому вы получаете различные прогоны, где еще выполняются значения >5 (например, 8 в вашем примере).

Какие итерации? общий счетчик итераций? или на поток? Я уверен, что это за поток. пожалуйста, одобрите.

Это индекс, передаваемый в Parallel.For. Break() не предотвратит обработку элементов, но гарантирует, что все элементы до 100 будут обработаны, но элементы выше 100 могут обрабатываться или не обрабатываться.

Я прав? вот почему я получаю более 5 элементов в моем примере?

Да. Если вы используете сортировщик, как вы показали, как только вы вызываете Break(), элементы, находящиеся за пределами того места, где вы ломаетесь, больше не будут планироваться. Тем не менее, уже запланированные элементы (это весь раздел) будут обработаны полностью. В вашем примере это означает, что вы, вероятно, всегда будете обрабатывать все 1000 элементов.

Как я могу по-настоящему сломать, когда (i == 5)?

Вы - но когда вы запускаете Parallel, все меняется. Какова действительная цель здесь? Если вы хотите обработать первые 6 элементов (0-5), вы должны ограничить элементы перед тем, как их пропустить через запрос LINQ или аналогичный. Затем вы можете обработать 6 элементов в Parallel.For или Parallel.ForEach без Break() и не беспокоиться.

Я имею в виду, давай! когда я делаю Break(), я хочу, чтобы цикл был остановлен. как и в обычном цикле For.

Вы должны использовать Stop() вместо Break(), если вы хотите, чтобы что-то останавливалось как можно быстрее. Это не будет препятствовать остановке элементов, которые уже запущены, но больше не будет планировать какие-либо элементы (в том числе и более низкие индексы или раньше в перечислении, чем ваша текущая позиция).

Ответ 2

Если Break вызывается из 100-й итерации цикла for, повторяющегося параллельно от 0 до 1000

100-я итерация цикла не обязательно (на самом деле, вероятно, нет), с индексом 99.

Ваши потоки могут и будут работать в неопределенном порядке. Когда встречается команда .Break(), никакие дальнейшие итерации цикла не будут запущены. Точно, когда это происходит, зависит от особенностей планирования потоков для конкретного прогона.

Я настоятельно рекомендую прочитать

Шаблоны параллельного программирования

(бесплатный PDF от Microsoft)

чтобы понять проектные решения и компромиссы в дизайне, которые вошли в TPL.

Ответ 3

Какие итерации? общий счетчик итераций? или на поток?

Отключить все запланированные итерации (или еще не запланированные).

Помните, что делегат может не работать, нет гарантии, что итерация i == 5 будет шестой, чтобы выполнить, скорее это вряд ли будет иметь место, за исключением редких случаев.

Q2: Я прав?

Нет, планирование не так упрощено. Скорее все задачи поставлены в очередь, а затем очередь обрабатывается. Но потоки каждый используют свою собственную очередь, пока она не станет пустой, когда они украдут из других потоков. Это не позволяет предсказать, какой поток будет обрабатывать делегат.

Если делегаты достаточно тривиальны, все может быть обработано в исходном потоке вызова (ни один другой поток не получает возможность украсть работу).

Q3: Как cn я действительно ломаюсь, когда (i == 5)?

Не используйте одновременно, если вам нужна линейная (в конкретной) обработке.

Метод Break предназначен для поддержки спекулятивного исполнения: попробуйте различные способы и остановитесь, как только все завершатся.