Widzę, że pytanie zostało reaktywowane z nagrodą, teraz pytam, jakie są praktyczne zastosowania yield
. Podam przykład z mojego doświadczenia.
Jak wiemy, yield
wymusza na wątku wywołującym rezygnację z procesora, na którym działa, aby można było zaplanować uruchomienie innego wątku. Jest to przydatne, gdy bieżący wątek zakończył na razie swoją pracę, ale chce szybko wrócić na początek kolejki i sprawdzić, czy jakiś warunek się zmienił. Czym to się różni od zmiennej warunkowej? yield
umożliwia wątkowi powrót do stanu działania o wiele szybciej. Podczas oczekiwania na zmienną warunku wątek jest zawieszany i musi czekać, aż inny wątek zasygnalizuje, że powinien kontynuować.yield
po prostu mówi: „pozwól działać innemu wątkowi, ale pozwól mi wrócić do pracy bardzo szybko, gdy spodziewam się, że coś bardzo szybko się zmieni w moim stanie”. Wskazuje to na zajęty wirowanie, w którym stan może się szybko zmienić, ale zawieszenie wątku spowodowałoby duży spadek wydajności.
Ale dość bełkotania, oto konkretny przykład: równoległy wzór czoła fali. Podstawowym przykładem tego problemu jest obliczanie poszczególnych „wysp” jedynek w dwuwymiarowej tablicy wypełnionej zerami i jedynkami. „Wyspa” to grupa komórek sąsiadujących ze sobą w pionie lub w poziomie:
1 0 0 0
1 1 0 0
0 0 0 1
0 0 1 1
0 0 1 1
Tutaj mamy dwie wyspy 1: lewy górny i prawy dolny.
Prostym rozwiązaniem jest wykonanie pierwszego przejścia przez całą tablicę i zastąpienie 1 wartości licznikiem zwiększającym się tak, że na końcu każda 1 została zastąpiona numerem kolejnym w wierszu głównym:
1 0 0 0
2 3 0 0
0 0 0 4
0 0 5 6
0 0 7 8
W następnym kroku każda wartość jest zastępowana przez minimum między sobą a wartościami sąsiadów:
1 0 0 0
1 1 0 0
0 0 0 4
0 0 4 4
0 0 4 4
Możemy teraz łatwo określić, że mamy dwie wyspy.
Część, którą chcemy uruchomić równolegle, to krok, w którym obliczamy minimum. Bez wchodzenia w zbyt wiele szczegółów każdy wątek otrzymuje wiersze w sposób przeplatany i opiera się na wartościach obliczonych przez wątek przetwarzający powyższy wiersz. W związku z tym każdy wątek musi być nieco opóźniony w stosunku do wątku przetwarzającego poprzednią linię, ale musi również nadążyć w rozsądnym czasie. Więcej szczegółów i implementację przedstawiam w tym dokumencie . Należy zauważyć, wykorzystanie sleep(0)
co jest mniej więcej równoważne C yield
.
W tym przypadku yield
została użyta w celu wymuszenia na każdym wątku z kolei wstrzymania, ale ponieważ w międzyczasie wątek przetwarzający sąsiedni rząd przesuwałby się bardzo szybko, zmienna warunkowa okazałaby się katastrofalnym wyborem.
Jak widać, yield
jest to dość drobnoziarnista optymalizacja. Używanie go w niewłaściwym miejscu, np. Oczekiwanie na rzadko zmieniający się warunek, spowoduje nadmierne wykorzystanie procesora.
Przepraszam za długą paplaninę, mam nadzieję, że wyraziłem się jasno.