Я вижу, что вопрос был возобновлен с щедростью, теперь спрашиваю, что практическое использование для yield
. Я приведу пример из моего опыта.
Как мы знаем, yield
заставляет вызывающий поток отказаться от процессора, на котором он работает, чтобы можно было запланировать запуск другого потока. Это полезно, когда текущий поток на данный момент завершил свою работу, но хочет быстро вернуться в начало очереди и проверить, изменилось ли какое-либо условие. Чем это отличается от условной переменной? yield
позволяет потоку намного быстрее вернуться в рабочее состояние. При ожидании переменной условия поток приостанавливается, и ему нужно дождаться, пока другой поток покажет, что он должен продолжить. yield
в основном говорит: «разрешить запуск другого потока, но позвольте мне вернуться к работе очень скоро, так как я ожидаю, что что-то очень быстро изменится в моем состоянии». Это намекает на занятое вращение, когда условие может быстро измениться, но приостановка потока приведет к значительному снижению производительности.
Но достаточно болтовни, вот конкретный пример: параллельный паттерн волнового фронта. Базовым примером этой проблемы является вычисление отдельных «островков» из 1 в двумерном массиве, заполненном 0 и 1. «Остров» - это группа ячеек, смежных друг с другом по вертикали или по горизонтали:
1 0 0 0
1 1 0 0
0 0 0 1
0 0 1 1
0 0 1 1
Здесь у нас есть два острова 1: верхний левый и правый нижний.
Простое решение состоит в том, чтобы сделать первый проход по всему массиву и заменить 1 значения счетчиком с приращением таким образом, чтобы к концу каждая 1 заменялась своим порядковым номером в главном порядке строки:
1 0 0 0
2 3 0 0
0 0 0 4
0 0 5 6
0 0 7 8
На следующем шаге каждое значение заменяется минимумом между собой и значениями его соседей:
1 0 0 0
1 1 0 0
0 0 0 4
0 0 4 4
0 0 4 4
Теперь мы можем легко определить, что у нас есть два острова.
Параллель, которую мы хотим выполнить параллельно, - это шаг, на котором мы вычисляем минимумы. Не вдаваясь в подробности, каждый поток получает строки с чередованием и полагается на значения, вычисленные потоком, обрабатывающим строку выше. Таким образом, каждый поток должен немного отставать от потока, обрабатывающего предыдущую строку, но также должен идти в ногу со временем. Более подробная информация и реализация представлены мной в этом документе . Обратите внимание на использование sleep(0)
, что является более или менее эквивалентом C yield
.
В этом случае yield
использовался для того, чтобы заставить каждый поток по очереди приостанавливаться, но поскольку поток, обрабатывающий соседнюю строку, в это время будет продвигаться очень быстро, условная переменная окажется катастрофическим выбором.
Как видите, yield
- это довольно тонкая оптимизация. Использование в неправильном месте, например ожидание состояния, которое редко изменяется, приведет к чрезмерному использованию ЦП.
Извините за долгую болтовню, надеюсь, я все прояснил.