Konkretne przykłady
Chciałbym dodać kilka przykładów z prawdziwego świata i połączyć je ze światem inżynierii oprogramowania. Najpierw rozważmy coś, co, mam nadzieję, pasuje do twojej intuicyjnej definicji „synchronicznej”: miganie świetlików , w pewnych okolicznościach. Po drugie, należy rozważyć 4x100 kobiet olimpijski przekaźnik wyścig . Po trzecie, rozważ ten stary trop z filmów wojskowych: „Mężczyźni, zsynchronizujcie swoje zegarki!”
Zastanówmy się, co się dzieje. Zacznijmy od zaobserwowania, że wszystkie te rzeczy są procesami lub bytami wydłużonymi w czasie . Nie ma sensu mówić, że miska jest „synchroniczna”, a kamień to „asynchroniczny”. Po drugie, tango wymaga dwóch . Nie można powiedzieć, że „biegacz jest zsynchronizowany”. Synchronizować z czym? Wreszcie, aby dwa procesy mogły zrobić coś w tym samym czasie, chyba że mają już dokładnie taką samą częstotliwość i fazę, jeden lub oba muszą poczekać .
Analiza
Kiedy definicja słownika mówi, że dwie istoty zsynchronizowane „występują lub istnieją jednocześnie”, bardzo ładnie się to zgadza z koncepcją światła świetlików. Niestety, powiedzenie, że światło jest „zsynchronizowane”, jest niechlujnym sposobem powiedzenia, że procesy oświetlenia świetlika są zsynchronizowane.
Jak więc kilka świetlików, które prawdopodobnie nie mają Apple SmartWatch i NTP do prowadzenia ich, jednocześnie mogą błysnąć tylnymi końcami? Cóż, jest to dość łatwe, jeśli mają środki na ustalenie spójnego tempa i mogą dokonać drobnych korekt. Po prostu migają, a jeśli więcej osób miga zaraz po nich, zwalniają (zwiększają opóźnienie), a jeśli więcej miga tuż przed nimi, przyspieszają (zmniejszają opóźnienie). Mogą więc użyć prostego procesu sprzężenia zwrotnego, aby osiągnąć zasadniczo to samo tempo i fazę. Ważną obserwacją tutaj jest zauważenie, że osiągają one synchronizację, czekając na odpowiedni moment, aby błysnąć .
Wyścig 4x100 jest interesujący, ponieważ widzisz obie formy pomiaru czasu w akcji: biegacze w zespole są zsynchronizowani, a biegacze w różnych zespołach są „asynchroniczni”. Drugi biegacz w sztafecie musi poczekać, aż pierwszy biegacz wejdzie do strefy transferu . Przekazanie jest wydarzeniem synchronicznym między tymi dwoma biegaczami. Jednak biegacze na różnych torach nie dbają o to, co dzieje się na innym torze , a na pewno nie zwalniają tempa i synchronizują swoje rozdania. Każdy tor biegaczy jest względem siebie asynchroniczny. Ponownie widzimy, że synchronizacja wymaga oczekiwania, podczas gdy asynchronia nie.
Wreszcie, żołnierze w spółce (plutonu, drużyny ogniowej, etc.) muszą synchronizować zegarki tak, że mogą zaatakować wroga w tym samym czasie . Może się zdarzyć, że niektórzy żołnierze dotrą na swoje pozycje przed innymi lub będą mieli okazję wcześniej strzelać do wroga. Ale jednoczesny atak jest na ogół bardziej skuteczny niż atak przypadkowy ze względu na element zaskoczenia. Aby więc osiągnąć synchronię, wielu żołnierzy musi czekać na wyznaczony czas na działanie.
Cechą
Skąd ten nacisk na czekanie? To dlatego, że czekanie jest funkcją definiującą, która odróżnia procesy synchroniczne od asynchronicznych. Jeśli masz dwa procesy, o których nic nie wiesz, domyślnie powinieneś założyć, że są one asynchroniczne. Na przykład dostawa paczki i przejazd karetką najprawdopodobniej nie są zsynchronizowane. Aby wykazać, że dwa procesy są w rzeczywistości zsynchronizowane, musisz znaleźć bardzo szczególny moment w czasie: punkt synchronizacji .
Kierowca dostarczający paczkę i karetka poganiająca kogoś do szpitala zazwyczaj nie dzielą żadnych punktów w czasie, które określamy jako „punkt synchronizacji”. Z drugiej strony świetliki migające jednocześnie, mają punkt synchronizacji za każdym razem, gdy migają, biegacze sztafetowi mają punkt synchronizacji za każdym razem, gdy oddają pałeczkę, a żołnierze mają punkt synchronizacji, kiedy rozpoczynają atak. Jeśli możesz zidentyfikować jeden lub więcej punktów synchronizacji, wówczas procesy są synchronizowane . Powinno to być łatwe do zrozumienia, ponieważ „syn-” to grecki przedrostek oznaczający „z” lub „razem”, a „chrono” to greckie określenie „czas”. „Zsynchronizowany” dosłownie oznacza „w tym samym czasie”,
Granic
Należy pamiętać, że „synchronizacja” niekoniecznie dotyczy całego okresu życia jednego lub obu procesów. Argumentowałbym, że dotyczy to tylko „czasu oczekiwania do punktów synchronizacji włącznie”. W ten sposób dwa procesy mogą działać asynchronicznie, dopóki nie osiągną stanu, w którym muszą się komunikować, a następnie synchronizują się, wymieniają informacje, a następnie kontynuują asynchronicznie. Prostym przykładem jest spotkanie z kimś na kawę. Oczywiście spotkanie jest punktem synchronizacji (a raczej wielu), a fakt, że dwie osoby przybywają do tego punktu, demonstruje synchronizację. Nie powiedzielibyśmy jednak tego, ponieważ dwie osoby spotkały się przy kawie, te dwa ludzkie życiasą „zsynchronizowane”. Być może była to jedyna chwila w ich życiu, którą poznali, a wszystko, co robią, jest poza tym niezależne.
Nie jest też tak, że przypadkowe spotkania demonstrują synchronizację. Jeśli dwóch nieznajomych mija się na ulicy, fakt, że są w określonym miejscu w pewnym momencie, nie dowodzi synchronizacji. Ani fakt, że jedna osoba siedzi na ławce i czeka na autobus, a druga zdarza się przechodzić obok. Procesy są synchroniczne tylko wtedy, gdy spotykają się w określonym celu .
Połączenie oprogramowania
Pomyślmy teraz o bardzo podstawowym zadaniu w oprogramowaniu: czytaniu z pliku. Jak zapewne wiesz, pamięć masowa jest zwykle tysiące do milionów razy wolniejsza niż pamięć podręczna lub pamięć główna. Z tego powodu systemy operacyjne i biblioteki języków programowania ogólnie oferują zarówno synchroniczne, jak i asynchroniczne operacje we / wy. Teraz, nawet jeśli twój program ma tylko jeden wątek, powinieneś myśleć o systemie operacyjnym jako o „osobnym procesie” na potrzeby tej dyskusji.
Synchronizacja
Kiedy wykonujesz „synchroniczny odczyt I / O”, twój wątek musi poczekać, aż dane będą dostępne, w którym to momencie będzie kontynuowany. Jest to bardzo podobne do biegacza sztafetowego, który przekazuje pałeczkę następnemu biegaczowi, ale wyobraź sobie sztafetę, w której tylko dwóch biegaczy biegnie dookoła toru, a drugi biegacz również wraca do pierwszego.
W tym przypadku wątek programu i proces we / wy systemu operacyjnego nie „dzieją się (działają) w tym samym czasie”, więc dziwne wydaje się stwierdzenie, że procesy te są „zsynchronizowane”. Ale to niewłaściwy sposób na to spojrzeć! To tak, jakby powiedzieć: „Biegacze w sztafecie nie biegają w tym samym czasie, więc nie są zsynchronizowani”. W rzeczywistości oba stwierdzenia są błędne! Biegacze z zespołu sztafetowego robią to i muszą biegać w tym samym czasie, ale tylko w bardzo konkretnym momencie: przekazanie pałki. W rzeczywistości tylko ten wyjątkowy moment podczas wyścigu przekonuje nas, że zespoły sztafetowe są zsynchronizowane na początek! Jeśli uznamy żądanie i odpowiedź we / wy jako „pałeczkę”,
Z drugiej strony, jeśli myślimy o czymś takim jak Analiza Elementów Skończonych na superkomputerze, widzimy, że tysiące procesów muszą działać krok po kroku, aby zaktualizować ogromny stan globalny. Nawet jeśli niektóre węzły zakończą swoją pracę dla danego kroku czasowego przed innymi, wszystkie muszą poczekać na ukończenie tego kroku czasowego, ponieważ wyniki rozprzestrzeniają się na sąsiadów w przestrzeni kosmicznej. Ten rodzaj synchronizacji przypomina świetliki: wszyscy aktorzy wykonują to samo zadanie.
Różnorodność procesów
Z tego powodu możemy wynaleźć kilka terminów, które pomogą nam zobaczyć, że dzieją się trzy rodzaje rzeczy: „jednorodna synchronizacja”, „heterogeniczna synchronizacja” i „sekwencyjna synchronizacja”. Kiedy więc aktorzy wykonują to samo zadanie jednocześnie (MES, świetliki), są „jednorodni”. Kiedy wykonują różne zadania jednocześnie (żołnierze biegają kontra czołgają się kontra płyną do celu, fizyka kontra dźwięk kontra wątki AI w grze), są „heterogeniczni”. Kiedy wykonują zadania pojedynczo, są „sekwencyjni” (biegacze przekaźników, blokują wejścia / wyjścia). Mogą wyglądać zupełnie inaczej, ale mają jedną istotną właściwość: wszystkie typy aktorów czekają, aby wszyscy dotarli do punktu synchronizacji w tym samym czasie. pomiędzy punktami synchronizacji lub „wykonanie tej samej akcji” nie ma znaczenia dla właściwości synchroniczności.
Rurociągi renderujące w GPU są synchroniczne, ponieważ wszystkie muszą razem zakończyć ramkę i razem rozpocząć nową ramkę. Są jednorodne, ponieważ wykonują ten sam rodzaj pracy i wszyscy są razem aktywni. Ale główna pętla gry serwera i blokujące wątki we / wy przetwarzające zdalne dane wejściowe są heterogeniczne, ponieważ wykonują bardzo różne rodzaje pracy, a niektóre wątki we / wy w ogóle nic nie robią, ponieważ nie wszystkie połączenia są używane. Mimo to są zsynchronizowane, ponieważ muszą udostępniać stan atomowo (gracz nie może zobaczyć częściowej aktualizacji świata gry, a serwer nie może zobaczyć tylko fragmentu danych wejściowych gracza).
Asynchronizacja
Rozważmy teraz „asynchroniczny odczyt we / wy”. Gdy program wysyła do systemu operacyjnego żądanie odczytania trochę danych z pamięci, połączenie natychmiast wraca . Zignorujmy callbacki i skupmy się na odpytywaniu. Ogólnie rzecz biorąc, moment, w którym dane są dostępne dla twojego programu, nie odpowiada żadnemu specjalnemu momentowi, jeśli chodzi o wątek twojego programu. Jeśli Twój program nie czeka wprost na dane, wątek nawet nie będzie wiedział dokładnie, kiedy ten moment nastąpi. Odkryje tylko, że dane czekają przy następnym sprawdzeniu.
Nie ma specjalnego czasu na spotkanie, w którym system operacyjny i wątek programu zgadzają się przekazać dane. Są jak dwa statki przepływające w nocy. Asynchronia charakteryzuje się brakiem oczekiwania. Oczywiście wątek programu często ostatecznie czeka na operację we / wy, ale nie musi. Z radością może kontynuować wykonywanie innych obliczeń podczas pobierania operacji we / wy i sprawdzić później, kiedy będzie miał chwilę do stracenia. Oczywiście po zakończeniu pobierania danych przez system operacyjny nie czeka i czeka. Po prostu umieszcza dane w dogodnym miejscu i kontynuuje swoją działalność. W tym przypadku jest tak, jakby program przekazał pałeczkę systemowi operacyjnemu, a system operacyjny pojawia się później, upuszcza pałeczkę na ziemię wraz z danymi i schodzi z toru. Program może, ale nie musi, czekać na odbiór przekazu.
Równoległość
Kiedy oznaczamy funkcję jako „asynchroniczną” w oprogramowaniu, często oznacza to, że chcemy równoległości . Pamiętaj jednak, że równoległość nie oznacza synchronizacji . Świetliki są dobrym przykładem, ponieważ one również wykazują zachowanie zarówno synchroniczne, jak i asynchroniczne. Podczas gdy większość much błysnęła w zgodzie, wiele z nich najwyraźniej nie pasowało do reszty grupy i błyskało bardziej losowo. Muchy mogły działać jednocześnie , ale nie wszystkie były zsynchronizowane .
Teraz, gdy oznaczamy jakiś kod jako „asynchroniczny”, wygląda to zabawnie, ponieważ sugeruje, że reszta kodu, który nie jest tak oznaczony, to „synchronizacja”. Co to w ogóle znaczy? Czy nie nalegaliśmy, aby „synchronizacja” wymagała dwóch tanga? Ale co jeśli mówimy o wykonywaniu kodu w jednym wątku? W takim przypadku musimy cofnąć się o krok i pomyśleć o programie jako sekwencji stanów i przejść między nimi. Instrukcja w programie powoduje zmianę stanu. Możemy myśleć o tym jako o „mikroprocesie”, który rozpoczyna się i kończy wraz ze stwierdzeniem. Punkty sekwencji zdefiniowane przez język są w rzeczywistości punktami synchronizacji tych „mikroprocesów”. W ten sposób możemy wyświetlić jednowątkowy,
Integralność języka programowania gwarantuje, że aktualizacje stanu nie zakłócają instrukcji, a punkty sekwencji określają granice, przez które kompilator nie może dokonywać obserwowalnych optymalizacji. Na przykład kolejność oceny wyrażeń w instrukcji może być nieokreślona lub nieokreślona, co daje kompilatorowi swobodę optymalizacji instrukcji na różne sposoby. Ale zanim rozpocznie się kolejna instrukcja, program powinien być w dobrze zdefiniowanym stanie, jeśli sam PL jest w dobrym stanie.
Do tej pory powinno być jasne, co rozumiemy przez „asynchronię”. Oznacza to dokładnie, że domniemany kontrakt synchronizacji w bloku kodu jest wyłączony dla bloku asynchronicznego. Dozwolona jest niezależna aktualizacja stanu programu, bez gwarancji bezpieczeństwa normalnie implikowanych przez sekwencyjny (spójny, synchroniczny) model obliczeniowy. Oczywiście oznacza to, że musimy zachować szczególną ostrożność, aby nie zniszczyć stanu programu z niekonsekwencją. Zazwyczaj oznacza to, że wprowadzamy ograniczoną, wyraźną synchronizację w celu koordynacji z blokiem asynchronicznym. Pamiętaj, że oznacza to, że blok asynchroniczny może być zarówno asynchroniczny, jak i synchroniczny w różnych momentach! Ale przypominając, że synchronizacja wskazuje jedynie na istnienie punktu synchronizacji, nie powinniśmy mieć problemów z zaakceptowaniem tego pojęcia.