Я бачу, що питання було відновлено щедро, тепер я задаю питання, для чого практичні користі yield
. Наведу приклад зі свого досвіду.
Як ми знаємо, yield
змушує викличний потік відмовитися від процесора, на якому він працює, щоб можна було запланувати інший потік. Це корисно, коли поточна нитка вже закінчила свою роботу, але хоче швидко повернутися до передньої частини черги і перевірити, чи змінилася якась умова. Чим це відрізняється від змінної умови? yield
дозволяє потоку повернутися набагато швидше до стану роботи. Під час очікування змінної умови потік призупиняється і потрібно чекати, коли інший потік подасть сигнал, що він повинен продовжуватися.yield
в основному каже: "дозвольте запустити іншу нитку, але дозвольте мені повернутися до роботи дуже скоро, оскільки я очікую, що щось дуже зміниться в моєму стані". Це натякає на зайняте спінінг, коли умова може швидко змінюватися, але призупинення потоку спричинить велику ефективність.
Але достатньо лепетання, ось конкретний приклад: паралельний малюнок хвилі фронту. Основний екземпляр цієї проблеми - обчислення окремих "островів" 1s у двовимірному масиві, заповненому 0s та 1s. "Острів" - це група комірок, які розташовані поруч з будь-яким вертикальним чи горизонтальним:
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)
яке більш-менш З еквівалентом yield
.
У цьому випадку yield
він використовувався для того, щоб примусити кожну нитку по черзі до паузи, але оскільки нитка, що обробляє сусідній рядок, тим часом просувається дуже швидко, змінна умова виявиться катастрофічним вибором.
Як бачимо, yield
досить тонка оптимізація зерна. Використання його в неправильному місці, наприклад, очікування за умови, яка рідко змінюється, призведе до надмірного використання ЦП.
Вибачте за довгу лайку, сподіваюся, що я дав зрозуміти.