Kiedy odpytywanie o zdarzenia byłoby lepsze niż stosowanie wzorca obserwatora?


41

Czy istnieją scenariusze, w których odpytywanie o zdarzenia byłoby lepsze niż stosowanie wzorca obserwatora ? Obawiam się, że użyję odpytywania i zacznę go używać, jeśli ktoś da mi dobry scenariusz. Mogę tylko myśleć o tym, jak wzorzec obserwatora jest lepszy niż odpytywanie. Rozważ ten scenariusz:

Programujesz symulator samochodowy. Samochód jest przedmiotem. Jak tylko samochód się włączy, chcesz odtworzyć klip dźwiękowy „vroom vroom”.

Możesz to wymodelować na dwa sposoby:

Odpytywanie : Odpytuj obiekt samochodu co sekundę, aby sprawdzić, czy jest włączony. Gdy jest włączony, odtwórz klip dźwiękowy.

Wzorzec obserwatora : Ustaw samochód jako obiekt wzorca obserwatora. Niech opublikuje zdarzenie „włączone” dla wszystkich obserwatorów, gdy samo się włączy. Utwórz nowy obiekt dźwiękowy, który nasłuchuje samochodu. Niech implementuje funkcję zwrotną „on”, która odtwarza klip dźwiękowy.

W tym przypadku myślę, że wzór obserwatora wygrywa. Po pierwsze, odpytywanie wymaga więcej procesora. Po drugie, klip dźwiękowy nie uruchamia się natychmiast po włączeniu samochodu. Z powodu okresu odpytywania może być do 1 sekundy przerwy.


Nie mogę wymyślić prawie żadnego scenariusza. Wzorzec obserwatora jest tym, co faktycznie odwzorowuje na prawdziwy świat i prawdziwe życie. Dlatego uważam, że żaden scenariusz nigdy nie uzasadniałby niestosowania go.
Saeed Neamati,

Czy mówisz o zdarzeniach interfejsu użytkownika , czy ogólnie o wydarzeniach?
Bryan Oakley

3
Twój przykład nie usuwa problemu z odpytywaniem / obserwowaniem. Po prostu przeszedłeś na niższy poziom. Twój program nadal musi dowiedzieć się, czy samochód jest włączony, czy nie przez jakiś mechanizm.
Dunk

Odpowiedzi:


55

Wyobraź sobie, że chcesz otrzymywać powiadomienia o każdym cyklu silnika, np. Aby wyświetlić pomiar prędkości obrotowej kierowcy.

Wzorzec obserwatora: silnik publikuje zdarzenie „cyklu silnika” wszystkim obserwatorom dla każdego cyklu. Utwórz detektor, który zlicza zdarzenia i aktualizuje ekran RPM.

Odpytywanie: Wyświetlacz RPM w regularnych odstępach czasu prosi silnik o licznik cykli silnika i odpowiednio aktualizuje wyświetlacz RPM.

W takim przypadku wzorzec obserwatora prawdopodobnie straciłby: cykl silnika jest procesem o wysokiej częstotliwości i wysokim priorytecie, nie chcesz opóźniać ani opóźniać tego procesu tylko w celu aktualizacji wyświetlacza. Nie chcesz także niszczyć puli wątków zdarzeniami cyklu silnika.


PS: Często używam wzorca odpytywania w programowaniu rozproszonym:

Wzorzec obserwatora: Proces A wysyła komunikat do procesu B, który mówi „za każdym razem, gdy wystąpi zdarzenie E, wyślij wiadomość do procesu A”.

Wzorzec sondowania: Proces A regularnie wysyła komunikat do procesu B, który mówi „jeśli zdarzenie E wystąpiło od czasu ostatniego sondowania, wyślij mi teraz wiadomość”.

Wzorzec odpytywania powoduje nieco większe obciążenie sieci. Ale wzorzec obserwatora ma również wady:

  • Jeśli proces A ulegnie awarii, nigdy nie zrezygnuje z subskrypcji, a proces B będzie próbował wysyłać do niego powiadomienia przez całą wieczność, chyba że będzie w stanie niezawodnie wykryć awarie zdalnego procesu (nie jest to łatwe)
  • Jeśli zdarzenie E jest bardzo częste i / lub powiadomienia zawierają dużo danych, wówczas proces A może otrzymać więcej powiadomień o zdarzeniach, niż może obsłużyć. Dzięki wzorowi odpytywania może po prostu dławić odpytywanie.
  • W układzie obserwatora wysokie obciążenie może powodować „tętnienia” w całym systemie. Jeśli używasz gniazd blokujących, te zmarszczki mogą przebiegać w obie strony.

1
Słuszna uwaga. Czasami lepiej jest zbyt ankietę ze względu na wydajność.
Falcon,

1
Pod uwagę bierze się również spodziewana liczba obserwatorów. Gdy oczekujesz dużej liczby obserwatorów, aktualizacja ich wszystkich z obserwowanych może stać się wąskim gardłem wydajności. Znacznie łatwiej jest po prostu zapisać gdzieś wartość i poprosić „obserwatorów”, aby sprawdzili tę wartość, gdy jej potrzebują.
Marjan Venema

1
„o ile nie jest w stanie niezawodnie wykryć zdalnych błędów procesu (nie jest to łatwe do zrobienia)”… z wyjątkiem odpytywania; Dlatego najlepszym rozwiązaniem jest zminimalizowanie odpowiedzi „nic się nie zmieniło”. +1, dobra odpowiedź.
pdr

2
@Jojo: Możesz, tak, ale następnie umieszczasz zasady, które powinny należeć do wyświetlacza w liczniku RPM. Być może użytkownik czasami chce mieć bardzo dokładny wyświetlacz RPM.
Zan Lynx,

2
@JoJo: Publikowanie każdego 100. wydarzenia to hack. Działa to dobrze tylko wtedy, gdy częstotliwość zdarzeń jest zawsze w odpowiednim zakresie, jeśli przetwarzanie zdarzenia nie trwa zbyt długo dla silnika, jeśli wszyscy abonenci potrzebują porównywalnej dokładności. I wymaga jednej operacji modułu na RPM, co (przy założeniu kilku tysięcy RPM) jest o wiele więcej pracy dla procesora niż kilka operacji odpytywania na sekundę.
nikie

7

Odpytywanie jest lepsze, jeśli proces odpytywania przebiega znacznie wolniej niż ankiety. Jeśli piszesz zdarzenia do bazy danych, często lepiej jest sondować wszystkich producentów zdarzeń, zbierać wszystkie zdarzenia, które miały miejsce od czasu ostatniego sondowania, a następnie zapisywać je w jednej transakcji. Jeśli spróbujesz zapisać każde zdarzenie w takim stanie, w jakim ono wystąpiło, być może nie będziesz w stanie nadążyć i ostatecznie będziesz mieć problemy po zapełnieniu kolejek wejściowych. Ma to również większy sens w rozproszonych systemach rozproszonych, w których opóźnienie jest wysokie lub konfiguracja i rozłączanie połączenia są drogie. Uważam, że systemy ankietowania są łatwiejsze do napisania i zrozumienia, ale w większości sytuacji obserwatorzy lub konsumenci kierowani zdarzeniami wydają się oferować lepszą wydajność (z mojego doświadczenia).


7

Odpytywanie jest o wiele łatwiejsze do pracy w sieci, gdy połączenia mogą się nie powieść, serwery mogą zostać wykonane itp. Pamiętaj, że na koniec dnia gniazdo TCP potrzebuje komunikatów „podtrzymujących”, w przeciwnym razie serwer przejmie klienta odszedł.

Odpytywanie jest również dobre, gdy chcesz aktualizować interfejs użytkownika, ale obiekty leżące u jego podstaw zmieniają się bardzo szybko , nie ma sensu aktualizować interfejsu użytkownika więcej niż kilka razy na sekundę w większości aplikacji.

Pod warunkiem, że serwer może zareagować „bez zmian” przy bardzo niskich kosztach i nie odpytujesz zbyt często i nie masz tysięcy sondujących klientów, wtedy sondowanie działa bardzo dobrze w prawdziwym życiu.

Jednak w przypadkach „ w pamięci ” domyślnie używam wzorca obserwatora, ponieważ zwykle jest to najmniejsza praca.


5

Sondowanie ma pewne wady, w zasadzie stwierdziłeś je już w swoim pytaniu.

Jednak może być lepszym rozwiązaniem, jeśli chcesz naprawdę oddzielić obserwowalne od obserwatorów. Ale czasem lepiej byłoby użyć obserwowalnego opakowania dla obserwowanego obiektu w takich przypadkach.

Używałbym odpytywania tylko wtedy, gdy nie można zaobserwować obserwowalnego przy interakcjach z obiektami, co często ma miejsce na przykład przy wyszukiwaniu w bazach danych, gdzie nie ma wywołań zwrotnych. Innym problemem może być wielowątkowość, gdzie często bezpieczniej jest odpytywać i przetwarzać wiadomości niż bezpośrednio wywoływać obiekty, aby uniknąć problemów z współbieżnością.


Nie jestem do końca pewien, dlaczego uważasz, że odpytywanie jest bezpieczniejsze dla wielowątkowości. W większości przypadków tak nie jest. Gdy procedura odpytywania odbiera żądanie odpytywania, musiała ustalić stan odpytywanego obiektu, jeśli obiekt jest w trakcie aktualizacji, to nie jest bezpieczny dla procedury odpytywania. W scenariuszu nasłuchiwania powiadomienia są wyświetlane tylko wtedy, gdy popychacz jest w spójnym stanie, dzięki czemu można uniknąć większości problemów z synchronizacją w odpytywanym obiekcie.
Lie Ryan,

4

Dobry przykład sytuacji, w której odpytywanie przejmuje powiadomienie, spójrz na stosy sieciowe systemu operacyjnego.

To była wielka sprawa dla Linuksa, kiedy stos sieciowy włączył NAPI, interfejs API sieci, który pozwalał sterownikom przejść z trybu przerwania (powiadomienia) do trybu odpytywania.

W przypadku wielu interfejsów Gigabit Ethernet przerywacze często przeciążają procesor, powodując, że system działa wolniej niż powinien. Podczas odpytywania karty sieciowe zbierają pakiety w buforach, aż do odpytywania lub karty nawet zapisują pakiety do pamięci za pośrednictwem DMA. Następnie, gdy system operacyjny jest gotowy, odpytuje kartę pod kątem wszystkich danych i wykonuje standardowe przetwarzanie TCP / IP.

Tryb odpytywania umożliwia procesorowi zbieranie danych Ethernet z maksymalną szybkością przetwarzania bez zbędnego obciążenia przerwania. Tryb przerwania pozwala procesorowi na bezczynność między pakietami, gdy praca nie jest tak zajęta.

Sekret polega na tym, kiedy przejść z jednego trybu do drugiego. Każdy tryb ma zalety i powinien być używany we właściwym miejscu.


2

Uwielbiam ankiety! Czy ja Tak! Czy ja Tak! Czy ja Tak! Czy nadal? Tak! Co teraz? Tak!

Jak wspomnieli inni, może być niewiarygodnie nieefektywny, jeśli będziesz sondować tylko po to, aby odzyskać ten sam niezmieniony stan w kółko. Taki jest przepis na spalanie cykli procesora i znaczne skrócenie żywotności baterii na urządzeniach mobilnych. Oczywiście nie jest to marnotrawstwo, jeśli odzyskujesz nowy i znaczący stan za każdym razem w tempie nie szybszym niż to pożądane.

Ale głównym powodem, dla którego uwielbiam ankiety, jest jej prostota i przewidywalność. Możesz prześledzić kod i łatwo zobaczyć, kiedy i gdzie coś się wydarzy oraz w jakim wątku. Jeśli teoretycznie żylibyśmy w świecie, w którym odpytywanie było znikomym marnotrawstwem (chociaż rzeczywistość jest daleka od tego), to uważam, że uprościłoby to utrzymywanie kodu jako ogromnej umowy. I to jest korzyść z odpytywania i ciągnięcia, ponieważ widzę, że moglibyśmy zignorować wydajność, chociaż nie powinniśmy w tym przypadku.

Kiedy zacząłem programować w erze DOS, moje małe gry obracały się wokół odpytywania. Skopiowałem część kodu asemblera z książki, którą ledwo rozumiałem, dotyczącą przerwania klawiatury i zapisałem bufor stanów klawiatury, w którym to momencie moja główna pętla zawsze odpytywała. Czy klawisz strzałki w górę jest wciśnięty? Nie. Czy klawisz strzałki w górę jest wciśnięty? Nie. A teraz? Nie. Teraz? Tak. Ok, rusz gracza.

I chociaż niezwykle marnotrawstwo, stwierdziłem, że o wiele łatwiej jest to uzasadnić w porównaniu do tych dni programowania wielozadaniowego i zdarzeń. Wiedziałem dokładnie, kiedy i gdzie coś się dzieje przez cały czas, i łatwiej było utrzymać stabilną i przewidywalną liczbę klatek bez czkawki.

Od tego czasu zawsze starałem się znaleźć sposób na uzyskanie niektórych korzyści i przewidywalności tego bez faktycznego spalania cykli procesora, takich jak używanie zmiennych warunkowych do powiadamiania wątków o przebudzeniu, w którym momencie mogą pobrać nowy stan, robić swoje i wracać do łóżka, czekając na powiadomienie.

I w jakiś sposób uważam, że kolejki zdarzeń są łatwiejsze do pracy z wzorcami niż obserwatorami, mimo że nadal nie są tak łatwe do przewidzenia, dokąd się wybierzesz i co się stanie. Przynajmniej scentralizują przepływ sterowania obsługą zdarzeń do kilku kluczowych obszarów w systemie i zawsze obsługują te zdarzenia w tym samym wątku zamiast podskakiwać z jednej funkcji do miejsca całkowicie odległego i niespodziewanego poza centralnym wątkiem obsługi zdarzeń. Tak więc dychotomia nie zawsze musi odbywać się między obserwatorami a ankietami. Kolejki zdarzeń są jakby pośrednikiem.

Ale tak, w jakiś sposób uważam, że o wiele łatwiej jest rozumować systemy, które wykonują rzeczy, które są analogicznie bliższe do rodzaju przewidywalnych przepływów kontrolnych, które miałem, kiedy sondowałem wieki temu, jednocześnie przeciwdziałając tendencji do pracy w czasy, kiedy nie nastąpiły żadne zmiany stanu. Jest więc taka korzyść, jeśli możesz to zrobić w sposób, który nie powoduje niepotrzebnego spalania cykli procesora, jak w przypadku zmiennych warunkowych.

Pętle homogeniczne

W porządku, otrzymałem świetny komentarz, Josh Caswellktóry wskazał na pewną głupotę w mojej odpowiedzi:

„jak używanie zmiennych warunkowych do powiadamiania wątków o przebudzeniu” Brzmi jak układ oparty na zdarzeniu / obserwatorze, a nie odpytywanie

Technicznie sama zmienna warunku stosuje wzorzec obserwatora do budzenia / powiadamiania wątków, więc nazwanie tego „odpytywaniem” byłoby prawdopodobnie niezwykle mylące. Ale uważam, że zapewnia podobną korzyść, jaką znalazłem jako odpytywanie z dni DOS (tylko pod względem przepływu kontroli i przewidywalności). Spróbuję to wyjaśnić lepiej.

W tamtych czasach podobało mi się to, że możesz spojrzeć na sekcję kodu lub prześledzić ją i powiedzieć: „Okej, cała ta sekcja jest poświęcona obsłudze zdarzeń na klawiaturze. W tej sekcji kodu nic więcej się nie wydarzy I wiem dokładnie, co się wydarzy wcześniej i wiem dokładnie, co się wydarzy później (np. Fizyka i rendering). ” Sondowanie stanów klawiatury zapewniło tego rodzaju centralizację przepływu kontroli w zakresie obsługi tego, co powinno nastąpić w odpowiedzi na to zdarzenie zewnętrzne. Nie zareagowaliśmy natychmiast na to zdarzenie zewnętrzne. Odpowiedzieliśmy na to w dogodnym dla nas czasie.

Kiedy używamy systemu opartego na wypychaniu opartego na wzorcu obserwatora, często tracimy te korzyści. Formant może zostać przeskalowany, co wyzwala zdarzenie zmiany rozmiaru. Kiedy go prześledzimy, stwierdzimy, że znajdujemy się w egzotycznej kontroli, która zmienia wiele niestandardowych rzeczy, co powoduje więcej zdarzeń. W efekcie jesteśmy całkowicie zaskoczeni śledzeniem wszystkich tych kaskadowych zdarzeń, co do tego, gdzie skończymy w systemie. Co więcej, możemy odkryć, że wszystko to nawet nie występuje konsekwentnie w danym wątku, ponieważ wątek A może tutaj zmienić rozmiar kontrolki, podczas gdy wątek B również zmienia rozmiar kontrolki później. Dlatego zawsze uważałem to za bardzo trudne do przewidzenia, biorąc pod uwagę, jak trudno jest przewidzieć, gdzie wszystko się wydarzy, a także co się stanie.

Kolejka zdarzeń jest dla mnie trochę łatwiejsza do uzasadnienia, ponieważ upraszcza to, gdzie wszystkie te rzeczy dzieją się przynajmniej na poziomie wątku. Jednak może się zdarzyć wiele różnych rzeczy. Kolejka zdarzeń może zawierać eklektyczną mieszankę zdarzeń do przetworzenia, a każda z nich może nas jeszcze zaskoczyć, jaka kaskada zdarzeń się wydarzyła, kolejność ich przetwarzania i jak odbijamy się po całym miejscu w bazie kodu .

To, co uważam za „najbliższe” odpytywaniu, nie użyłoby kolejki zdarzeń, ale odroczyłoby bardzo jednorodny rodzaj przetwarzania. A PaintSystemmoże zostać zaalarmowany przez zmienną warunkową, że do odmalowania niektórych komórek siatki okna należy wykonać malowanie, w którym to momencie wykonuje prostą sekwencyjną pętlę przez komórki i odświeża wszystko w środku w odpowiedniej kolejności Z. Może istnieć jeden poziom wywołania pośredniej / dynamicznej wysyłki, aby wywołać zdarzenia malowania w każdym widgecie znajdującym się w komórce, którą należy odmalować, ale to wszystko - tylko jedna warstwa wywołań pośrednich. Zmienna warunkowa używa wzorca obserwatora, aby ostrzec PaintSystem, że ma pracę do wykonania, ale nie określa nic więcej, aPaintSystemjest w tym momencie poświęcony jednemu jednorodnemu, bardzo jednorodnemu zadaniu. Kiedy debugujemy i PaintSystem'sśledzimy kod, wiemy, że nic innego się nie wydarzy oprócz malowania.

Chodzi więc głównie o sprowadzenie systemu do miejsca, w którym te rzeczy wykonują jednorodne pętle w stosunku do danych, nakładając na to bardzo szczególną odpowiedzialność zamiast niejednorodnych pętli w stosunku do różnych typów danych, wykonując wiele obowiązków, jakie możemy uzyskać przy przetwarzaniu kolejki zdarzeń.

Dążymy do tego typu rzeczy:

when there's work to do:
   for each thing:
       apply a very specific and uniform operation to the thing

W przeciwieństwie do:

when one specific event happens:
    do something with relevant thing
in relevant thing's event:
    do some more things
in thing1's triggered by thing's event:
    do some more things
in thing2's event triggerd by thing's event:
    do some more things:
in thing3's event triggered by thing2's event:
    do some more things
in thing4's event triggered by thing1's event:
    cause a side effect which shouldn't be happening
    in this order or from this thread.

I tak dalej. I nie musi to być jeden wątek na zadanie. Jeden wątek może zastosować logikę układów (zmiana rozmiaru / repozycjonowanie) do kontrolek GUI i odmalować je, ale może nie obsługiwać kliknięć klawiatury lub myszy. Możesz więc spojrzeć na to jako na poprawę jednorodności kolejki zdarzeń. Ale nie musimy też używać kolejki zdarzeń i przeplatać funkcji zmiany rozmiaru i malowania. Możemy zrobić jak:

in thread dedicated to layout and painting:
    when there's work to do:
         for each widget that needs resizing/reposition:
              resize/reposition thing to target size/position
              mark appropriate grid cells as needing repainting
         for each grid cell that needs repainting:
              repaint cell
         go back to sleep

Tak więc powyższe podejście wykorzystuje tylko zmienną warunkową, aby powiadomić wątek, gdy jest praca do wykonania, ale nie przeplata różnych rodzajów zdarzeń (zmiana rozmiaru w jednej pętli, malowanie w innej pętli, a nie mieszanka obu) i nie „ t zawracał sobie głowę komunikowaniem, co dokładnie należy wykonać (wątek „odkrywa” to po przebudzeniu, patrząc na ogólnosystemowe stany ECS). Każda wykonywana przez niego pętla ma wtedy bardzo jednorodny charakter, co ułatwia ustalenie kolejności, w której wszystko się dzieje.

Nie jestem pewien, jak nazwać tego rodzaju podejście. Nie widziałem, żeby robiły to inne silniki GUI i jest to moje własne egzotyczne podejście do mojego. Ale zanim spróbowałem zaimplementować wielowątkowe frameworki GUI przy użyciu obserwatorów lub kolejek zdarzeń, miałem ogromne trudności z debugowaniem go, a także natknąłem się na pewne niejasne warunki wyścigowe i impasy, których nie byłem wystarczająco inteligentny, aby naprawić w sposób, który dał mi pewność siebie na temat rozwiązania (niektóre osoby mogą to zrobić, ale nie jestem wystarczająco inteligentny). Mój pierwszy projekt iteracji po prostu nazwał miejsce bezpośrednio przez sygnał, a niektóre miejsca następnie odradzały inne wątki, aby wykonać pracę asynchroniczną, i to było najtrudniejsze do uzasadnienia, a ja potykałem się o warunki wyścigu i impasy. Druga iteracja wykorzystywała kolejkę zdarzeń, co było nieco łatwiejsze do uzasadnienia, ale nie jest to wystarczająco łatwe, aby mój mózg mógł to zrobić, nie wpadając w niejasny impas i warunki wyścigu. Trzecia i ostatnia iteracja wykorzystała podejście opisane powyżej, a na koniec pozwoliło mi to na stworzenie wielowątkowego frameworku GUI, który nawet głupi prostak taki jak ja mógłby poprawnie zaimplementować.

Wtedy ten rodzaj ostatecznego wielowątkowego interfejsu GUI pozwolił mi wymyślić coś innego, co było o wiele łatwiejsze do uzasadnienia i uniknięcie tego rodzaju błędów, które zwykle popełniłem, i jeden z powodów, dla których tak łatwo było mi to uzasadnić w najmniej z powodu tych jednorodnych pętli i tego, jak trochę przypominały one sterowanie, podobnie jak podczas odpytywania w dniach DOS (nawet jeśli tak naprawdę nie odpytuje i wykonuje pracę tylko wtedy, gdy jest do zrobienia). Chodziło o to, aby odejść jak najdalej od modelu obsługi zdarzeń, co pociąga za sobą niejednorodne pętle, niejednorodne skutki uboczne, niejednorodne przepływy kontrolne, i coraz bardziej pracować w kierunku jednorodnych pętli działających jednorodnie na jednorodnych danych i izolowaniu i ujednolicające skutki uboczne w taki sposób, że łatwiej było skoncentrować się na „czym”


1
„jak używanie zmiennych warunkowych do powiadamiania wątków o przebudzeniu” Brzmi jak układ oparty na zdarzeniach / obserwator, a nie odpytywanie.
Josh Caswell

Uważam, że różnica jest bardzo subtelna, ale powiadomienie ma formę „Jest praca do zrobienia”, aby obudzić wątki. Na przykład wzorzec obserwatora może przy zmianie rozmiaru kontroli nadrzędnej kaskadowe zmiany rozmiaru wywoływały wywołania w dół hierarchii przy użyciu dynamicznej wysyłki. Rzeczy miałyby swoje funkcje zmiany rozmiaru bezpośrednio wywoływane pośrednio. Wtedy mogą odświeżyć się natychmiast. Następnie, jeśli użyjemy kolejki zdarzeń, zmiana rozmiaru kontrolki nadrzędnej może przesunąć zdarzenia zmiany rozmiaru w dół hierarchii, w którym to momencie funkcje zmiany rozmiaru dla każdej kontrolki mogą zostać wywołane w odroczony sposób, w którym ...

... zwracają uwagę, że mogą wtedy przepchnąć przemalowane zdarzenia, które podobnie są wywoływane w odroczony sposób po zakończeniu zmiany rozmiaru wszystkiego, a wszystko z centralnego wątku obsługi zdarzeń. I uważam, że centralizacja jest trochę korzystna przynajmniej w zakresie debugowania i łatwego rozumowania, gdzie odbywa się przetwarzanie (w tym jaki wątek) ... Zatem to, co uważam za najbliższe odpytywaniu, nie jest żadnym te rozwiązania ...

Byłoby to na przykład LayoutSystemnormalnie śpiące, ale gdy użytkownik zmieni rozmiar kontrolki, użyje zmiennej warunkowej, aby obudzić LayoutSystem. Następnie LayoutSystemzmienia rozmiar wszystkich niezbędnych elementów sterujących i wraca do snu. W tym procesie prostokątne regiony, w których znajdują się widżety, są oznaczane jako wymagające aktualizacji, w którym to momencie PaintSystembudzi się i przechodzi przez te prostokątne regiony, odmalowując te, które wymagają przerysowania w płaskiej sekwencyjnej pętli.

Tak więc sama zmienna warunku podąża za wzorcem obserwatora, aby powiadomić wątki o przebudzeniu, ale nie przekazujemy żadnych informacji więcej niż „praca jest do zrobienia”. I każdy system, który się budzi, poświęcony jest przetwarzaniu rzeczy w bardzo prostej pętli z zastosowaniem bardzo jednorodnego zadania, w przeciwieństwie do kolejki zdarzeń, która ma niejednorodne zadania (może zawierać eklektyczną mieszankę zdarzeń do przetworzenia).

-4

Przedstawiam wam więcej na temat koncepcyjnego sposobu myślenia o tupotie obserwatora. Pomyśl o scenariuszu, takim jak subskrybowanie kanałów YouTube. Istnieje liczba użytkowników, którzy subskrybują kanał, a gdy na kanale pojawi się jakakolwiek aktualizacja zawierająca wiele filmów, subskrybent otrzyma powiadomienie o zmianie w tym konkretnym kanale. Doszliśmy zatem do wniosku, że jeśli kanał jest SUBJECT, który ma możliwość subskrybowania, anuluj subskrypcję i powiadom wszystkich OBSERWATORÓW zarejestrowanych na kanale.


2
to nawet nie próbuje odpowiedzieć na zadane pytanie, kiedy odpytywanie o zdarzenia byłoby lepsze niż używanie wzorca obserwatora. Zobacz, jak odpowiedzieć
gnat
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.