Korporacja jedności a wątki

13

Jaka jest różnica między koroutyną a nicią? Czy są jakieś zalety używania jednego nad drugim?

StrengthPlusPlus
źródło
3
Korpusy pracujące nad głównym wątkiem.
Woltus,
2
Nie możesz używać żadnych funkcji Unity w wątku. Coroutines mogą.
Hellium,
1
@Hellium Correction, nie można używać żadnych funkcji Unity w innym wątku, tzn. Funkcji Unity można używać w głównym wątku .
Pharap,

Odpowiedzi:

24

Chociaż na pierwszy rzut oka wydaje się, że Coroutines działają jak wątki, w rzeczywistości nie używają wielowątkowości. Są one wykonywane sekwencyjnie, aż do momentu yield. Silnik sprawdzi wszystkie uzyskane coroutines jako część własnej głównej pętli (w którym momencie dokładnie zależy od rodzaju yield, sprawdź ten schemat, aby uzyskać więcej informacji ), kontynuuje je jeden po drugim, aż do następnej yield, a następnie przejdzie do głównej pętli.

Zaletą tej techniki jest to, że można używać coroutines bez bólów głowy spowodowanych problemami z prawdziwym wielowątkowością. Nie dostaniesz żadnych zakleszczeń, warunków wyścigu ani problemów z wydajnością spowodowanych przez przełączniki kontekstu, będziesz mógł poprawnie debugować i nie musisz używać bezpiecznych dla wątków kontenerów danych. Dzieje się tak, ponieważ podczas wykonywania coroutine silnik Unity jest w stanie kontrolowanym. Korzystanie z większości funkcji Unity jest bezpieczne.

Z drugiej strony z wątkami nie masz absolutnie żadnej wiedzy o tym, w jakim stanie znajduje się obecnie główna pętla Unity (może w rzeczywistości już nie działać). Więc twój wątek może spowodować wiele spustoszenia, robiąc coś naraz, nie powinno to robić. Nie dotykaj żadnej natywnej funkcjonalności Unity z pod-wątku . Jeśli chcesz komunikować się między wątkiem głównym a głównym wątkiem, poproś, aby wątek zapisał w jakimś bezpiecznym (!) Obiekcie kontenerowym i MonoBehaviour odczytał tę informację podczas zwykłych funkcji zdarzenia Unity.

Wadą braku robienia „rzeczywistych” wielowątkowości jest to, że nie można używać coroutines do równoległego obliczania intensywnego procesora na wielu rdzeniach procesora. Możesz ich jednak użyć do podzielenia obliczeń na wiele aktualizacji. Zamiast zamrozić grę na sekundę, otrzymujesz niższą średnią liczbę klatek na sekundę. Ale w takim przypadku jesteś odpowiedzialny za yieldswoją korupcję, ilekroć chcesz pozwolić Unity na uruchomienie aktualizacji.

Wniosek:

  • Jeśli chcesz użyć wykonywania asynchronicznego do wyrażenia logiki gry, użyj coroutines.
  • Jeśli chcesz użyć wykonywania asynchronicznego w celu wykorzystania wielu rdzeni procesora, użyj wątków.
Philipp
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
MichaelHouse
10

Korpusy nazywamy w informatyce „kooperacyjną wielozadaniowością”. Są sposobem, w jaki wiele różnych strumieni wykonania współpracuje ze sobą. W wielozadaniowości kooperacyjnej jeden strumień wykonania ma wyłączną niekwestionowaną własność procesora, dopóki nie osiągnie wartości yield. W tym momencie Unity (lub jakikolwiek inny framework, którego używasz) ma opcję przełączenia na inny strumień wykonywania. Następnie uzyskuje wyłączną niekwestionowaną własność procesora, dopóki nie zostanie yield.

Wątki nazywamy „zapobiegawczym wielozadaniowością”. Kiedy używasz wątki zastrzega sobie prawo ramowe każdej chwili przerwać wątek w połowie myśli i przełączyć się do innego wątku. Nie ważne gdzie jesteś. W niektórych przypadkach możesz nawet zostać zatrzymany przez zapisanie zmiennej w pamięci!

Istnieją zalety i wady dla każdego. Wady korporacji są prawdopodobnie najłatwiejsze do zrozumienia. Po pierwsze, coroutines wszystkie wykonują się na jednym rdzeniu. Jeśli masz czterordzeniowy procesor, coroutines będą używać tylko jednego z czterech rdzeni. Upraszcza to rzeczy, ale w niektórych przypadkach może powodować problemy z wydajnością. Drugi minus polega na tym, że musisz zdawać sobie sprawę, że każda koruta może zatrzymać cały program po prostu odmawiając yield. To był problem na Mac OS9, wiele lat temu. OS9 obsługiwał tylko wielozadaniowość kooperacyjną na całym komputerze. Jeśli jeden z Twoich programów zawiesił się, mogło to zatrzymać komputer tak gwałtownie, że system operacyjny nie mógł nawet renderować tekstu komunikatu o błędzie, aby poinformować Cię, co się stało!

Zalety koroutyn polega na tym, że są one stosunkowo łatwe do zrozumienia. Błędy, które masz, są znacznie bardziej przewidywalne. Zwykle wymagają też mniej zasobów, co może być pomocne, gdy wspinasz się na dziesiątki tysięcy koroutyn lub wątków. Candid Moon wspomniał w komentarzach, że jeśli nie studiowałeś właściwie nici, po prostu trzymaj się coroutines i mają rację. Coroutines są znacznie prostsze w obsłudze.

Nici są zupełnie inną bestią. Zawsze musisz mieć się na baczności przed możliwością, że inny wątek może cię przerwać w dowolnym momenciei zepsuć swoje dane. Biblioteki wątków dostarczają całe spektrum potężnych narzędzi, które mogą ci w tym pomóc, takich jak muteksy i zmienne warunkowe, które pomagają poinformować system operacyjny, kiedy jest bezpieczny, aby uruchomić jeden z pozostałych wątków, a kiedy jest niebezpieczny. Istnieją całe kursy poświęcone temu, jak dobrze korzystać z tych narzędzi. Jednym ze słynnych problemów, które się pojawiają, jest „impas”, gdy dwa wątki „utkną”, czekając, aż drugi uwolni część zasobów. Inną kwestią, która jest bardzo ważna dla Unity, jest to, że wiele bibliotek (takich jak Unity) nie jest zaprojektowanych do obsługi połączeń z wielu wątków. Możesz bardzo łatwo złamać swoje ramy, jeśli nie zwrócisz uwagi na to, które połączenia są dozwolone, a które zabronione.

Powód tej dodatkowej złożoności jest w rzeczywistości bardzo prosty. Zapobiegawczy model wielozadaniowości jest naprawdę podobny do modelu wielowątkowości, który pozwala nie tylko przerywać inne wątki, ale faktycznie uruchamiać wątki obok siebie na różnych rdzeniach. Jest to niezwykle potężne, ponieważ jest to jedyny sposób, aby naprawdę wykorzystać te nowe procesory czterordzeniowe i kod szesnastkowy, które wychodzą, ale otwiera pole pandory. Reguły synchronizacji dotyczące zarządzania tymi danymi w świecie wielowątkowym są bardzo brutalne. W świecie C ++ są całe artykuły poświęcone temu, MEMORY_ORDER_CONSUMEktóry jest jednym z wielu wątków synchronizacji wielowątkowej.

Więc wady wątków? Proste: są trudne. Możesz natknąć się na całe klasy błędów, których nigdy wcześniej nie widziałeś. Wiele z nich to tak zwane „heisenbugi”, które czasem się pojawiają, a następnie znikają po ich debugowaniu. Narzędzia, które otrzymujesz, aby sobie z nimi poradzić, są bardzo potężne, ale mają również bardzo niski poziom. Zostały zaprojektowane tak, aby były wydajne w architekturze nowoczesnych układów, a nie były łatwe w użyciu.

Jeśli jednak chcesz wykorzystać całą moc procesora, są to potrzebne narzędzie. Ponadto, nie faktycznie algorytmy, które są łatwiejsze do zrozumienia niż w wielowątkowość są z współprogram po prostu dlatego, że niech uchwyt OS wszystkie pytania dotyczące tego, gdzie może nastąpić przerwy.

Polecam również Candid Moon, by trzymać się coroutines. Jeśli chcesz mocy wątków, zaangażuj się w to. Wyjdź i naprawdę ucz się formalnie. Mieliśmy kilkadziesiąt lat, aby dowiedzieć się, jak zorganizować najlepszy sposób myślenia o wątkach, aby wcześnie uzyskać bezpieczne, powtarzalne wyniki i zwiększyć wydajność z biegiem czasu. Na przykład wszystkie rozsądne kursy nauczą muteksów przed nauczeniem zmiennych warunków. Wszystkie rozsądne kursy, które obejmują atomikę, w pełni nauczą muteksów i zmiennych warunkowych, zanim nawet wspomną o istnieniu atomów. (Uwaga: nie ma czegoś takiego jak rozsądny samouczek na temat atomów.) Spróbuj nauczyć się nawlekania fragmentarycznego, a będziesz błagać o migrenę.

Cort Ammon
źródło
Wątki zwiększają złożoność głównie w przypadkach, gdy operacje i zależności są przeplatane. Jeśli główna pętla gry zawiera trzy funkcje, x (), y () i z () i żadna z nich nie wpływa na wszystko, co jest potrzebne innej, uruchomienie wszystkich trzech jednocześnie, ale następnie oczekiwanie na zakończenie wszystkich przed kontynuowaniem może pozwalają uzyskać pewne korzyści z maszyny wielordzeniowej bez konieczności nadmiernego komplikowania. Natomiast zmienne stanu są zazwyczaj używane w połączeniu z muteksy, paradygmat niezależne równoległe-kroki nie potrzebuje muteksy jako takie ...
Supercat
... ale po prostu sposób, w jaki wątki obsługujące y () i z () czekają, aż zostaną uruchomione, a następnie sposób, aby główny wątek czekał po uruchomieniu x (), aż y () i z () zostały zakończone.
supercat
@ supercat Zawsze musisz mieć pewną synchronizację, aby przechodzić między niezależnymi fazami równoległymi i fazami sekwencyjnymi. Czasami to nic więcej join(), ale potrzebujesz czegoś. Jeśli nie masz architekta, który zaprojektowałby system do synchronizacji, musisz to napisać sam. Jako ktoś, kto robi rzeczy wielowątkowe, uważam, że ludzkie modele myślenia o tym, jak działają komputery, wymagają dostosowania, zanim bezpiecznie wykonają synchronizację (czego nauczą dobre kursy)
Cort Ammon
Oczywiście trzeba trochę zsynchronizować, a osiągnięcie najwyższej wydajności na ogół wymaga czegoś więcej niż join. Chodzi mi o to, że dążenie do uzyskania umiarkowanej części możliwych korzyści związanych z gwintowaniem, łatwo, czasami może być lepsze niż stosowanie bardziej skomplikowanego podejścia do gwintowania w celu uzyskania większej części.
supercat
O nowych rodzajach błędów: pamiętaj również, że jeśli nie możesz logicznie udowodnić, że kod jest bezpieczny, nie można wiedzieć, jak błędny będzie za drzwiami. Chociaż kolejność wykonywania może być niezdefiniowana, to często przybiera podobne ścieżki przy każdym uruchomieniu na 1 komputerze. Często zdarza się, że zawiesza się ciężko i często na ułamku maszyn i nie można testować na wszystkich możliwych maszynach. W pracy mieliśmy błąd, który pojawił się tylko na 1 z naszych maszyn, tylko jeśli logowanie było wyłączone; wyśledzenie go zajęło wielu osobom. Nie chcę tego na wolności. Nie tylko testuj synchronizację, udowodnij to logicznie.
Aaron,
2

Najprościej mówiąc ...


Wątki

Wątek nie decyduje o tym, kiedy ustąpi, system operacyjny („OS”, np. Windows) decyduje, kiedy zostanie wydany. System operacyjny jest prawie całkowicie odpowiedzialny za planowanie wątków, decyduje, które wątki uruchomić, kiedy je uruchomić i jak długo.

Ponadto wątek może być uruchamiany synchronicznie (jeden wątek po drugim) lub asynchronicznie (różne wątki działające na różnych rdzeniach procesora). Możliwość asynchronicznego działania oznacza, że ​​wątki mogą wykonać więcej pracy w tym samym czasie (ponieważ wątki dosłownie wykonują dwie rzeczy jednocześnie). Nawet wątki synchroniczne wykonują wiele pracy, jeśli system operacyjny dobrze je planuje.

Jednak ta dodatkowa moc przetwarzania wiąże się z efektami ubocznymi. Na przykład, jeśli dwa wątki próbują uzyskać dostęp do tego samego zasobu (np. Listy), a każdy wątek może zostać losowo zatrzymany w dowolnym punkcie kodu, modyfikacje drugiego wątku mogą zakłócać modyfikacje dokonane przez pierwszy wątek. (Zobacz także: Warunki wyścigu i impas ).

Wątki są również uważane za „ciężkie”, ponieważ mają dużo narzutu, co oznacza, że ​​przy wymianie wątków poniesiona zostanie znaczna kara czasowa.


Coroutines

W przeciwieństwie do wątków, coroutine są całkowicie synchroniczne, tylko jedna coroutine może być uruchomiona w dowolnym momencie. Dodatkowo, coroutines mogą wybrać, kiedy ustąpić, a tym samym mogą ustąpić w punkcie kodu, który jest dogodny (np. Na końcu cyklu pętli). Ma to tę zaletę, że warunki wyścigu i impasy są o wiele łatwiejsze do uniknięcia, a także ułatwiają współpracę między coroutines.

Jednak jest to również główna odpowiedzialność, jeśli korupcja nie da się odpowiednio wydać, może skończyć się zużyciem dużej ilości czasu procesora i nadal może powodować błędy, jeśli nieprawidłowo zmodyfikuje współdzielone zasoby.

Korpusy na ogół nie wymagają przełączania kontekstu i dlatego szybko się włączają i wyłączają i są dość lekkie.


W podsumowaniu:

Wątek:

  • Synchroniczny lub asynchroniczny
  • Uzyskane przez system operacyjny
  • Wydajność losowa
  • Ciężki

Coroutine:

  • Synchroniczny
  • Daje samo
  • Plony z wyboru
  • Lekki

Role wątków i korporacji są bardzo podobne, ale różnią się sposobem wykonania pracy, co oznacza, że ​​każda z nich jest lepiej dostosowana do różnych zadań. Wątki najlepiej nadają się do zadań, w których mogą skupić się na samodzielnym robieniu czegoś bez przerywania, a następnie sygnalizowaniu, gdy są gotowe. Coroutyny najlepiej nadają się do zadań, które można wykonać w wielu małych krokach i zadań wymagających wspólnego przetwarzania danych.

Pharap
źródło