Próbuję zrozumieć, czym jest pętla zdarzeń. Często wyjaśnia się, że w pętli zdarzeń robisz coś, dopóki nie zostaniesz powiadomiony o wystąpieniu zdarzenia. Następnie zajmujesz się zdarzeniem i kontynuujesz robienie tego, co robiłeś wcześniej.
Aby zmapować powyższą definicję na przykładzie. Mam serwer, który „nasłuchuje” w pętli zdarzeń, a gdy zostanie wykryte połączenie przez gniazdo, dane z niego zostaną odczytane i wyświetlone, po czym serwer wznowi / zacznie nasłuchiwać tak jak wcześniej.
Jednak to wydarzenie się dzieje i otrzymujemy powiadomienie „tak po prostu”, to dla mnie zbyt wiele. Możesz powiedzieć: „To nie jest tak po prostu”, musisz zarejestrować detektora zdarzeń ”. Ale czym jest detektor zdarzeń, ale funkcja, która z jakiegoś powodu nie powraca. Czy jest w swojej własnej pętli i czeka na powiadomienie o zdarzeniu? Czy detektor zdarzeń powinien również zarejestrować detektor zdarzeń? Gdzie to się kończy?
Wydarzenia to fajna abstrakcja do pracy, jednak tylko abstrakcja. Uważam, że w końcu odpytywanie jest nieuniknione. Być może nie robimy tego w naszym kodzie, ale robią to za nas niższe poziomy (implementacja języka programowania lub system operacyjny).
Zasadniczo sprowadza się do następującego pseudo kodu, który działa gdzieś wystarczająco nisko, więc nie powoduje zajętego oczekiwania:
while(True):
do stuff
check if event has happened (poll)
do other stuff
Takie jest moje rozumienie całego pomysłu i chciałbym usłyszeć, czy jest to poprawne. Otwarcie zgadzam się z tym, że cały pomysł jest zasadniczo błędny, w takim przypadku chciałbym uzyskać prawidłowe wyjaśnienie.
źródło
EventSource
robi, jeśli nie odpytuje wejścia klawiatury?Odpowiedzi:
Większość pętli zdarzeń zostanie zawieszonych, jeśli nie będą gotowe żadne zdarzenia, co oznacza, że system operacyjny nie da zadania zadaniu do czasu wystąpienia zdarzenia.
Powiedz, że zdarzenie jest wciśnięte. Możesz zapytać, czy gdzieś w systemie operacyjnym jest pętla sprawdzająca naciśnięcia klawiszy. Odpowiedź brzmi nie. Naciśnięcie klawiszy generuje przerwanie , które jest obsługiwane asynchronicznie przez sprzęt. Podobnie w przypadku timerów, ruchów myszy, nadchodzącego pakietu itp.
W rzeczywistości dla większości systemów operacyjnych odpytywanie o zdarzenia jest abstrakcją. Sprzęt i system operacyjny obsługują zdarzenia asynchronicznie i umieszczają je w kolejce, którą mogą odpytywać aplikacje. Prawdziwe odpytywanie jest widoczne tylko na poziomie sprzętowym w systemach wbudowanych, a nawet tam nie zawsze.
źródło
Most event loops will block
. Jak to pasuje do „paradygmatu pętli zdarzeń, w przeciwieństwie do używania wątków, wykorzystuje nieblokujące wywołania asynchroniczne”?Myślę o odbiorniku zdarzeń nie jako o funkcji działającej we własnej pętli, ale jako o sztafecie z pierwszym biegaczem czekającym na pistolet startowy. Ważnym powodem używania zdarzeń zamiast odpytywania jest to, że są one bardziej wydajne przy cyklach procesora. Dlaczego? Spójrz na to od strony sprzętowej (zamiast kodu źródłowego).
Rozważ serwer WWW. Kiedy serwer dzwoni
listen()
i blokuje, kod zajmuje jego miejsce jako przekaźnik. Gdy nadejdzie pierwszy pakiet nowego połączenia, karta sieciowa rozpoczyna wyścig, przerywając system operacyjny. System operacyjny uruchamia procedurę obsługi przerwań (ISR), która pobiera pakiet. ISR przekazuje pałeczkę do procedury wyższego poziomu, która ustanawia połączenie. Po nawiązaniu połączenia procedura przekazuje pałeczkę dolisten()
, co przekazuje pałeczkę do kodu. W tym momencie możesz robić, co chcesz, korzystając z połączenia. Z tego co wiemy, między wyścigami każdy biegacz sztafetowy może iść do pubu. Siłą abstrakcji zdarzeń jest to, że Twój kod nie musi wiedzieć ani się tym przejmować.Niektóre systemy operacyjne zawierają kod obsługi zdarzeń, który uruchamia swoją część wyścigu, odkłada pałeczkę, a następnie zapętla się z powrotem do punktu początkowego, aby czekać na rozpoczęcie następnego wyścigu. W tym sensie obsługa zdarzeń jest zoptymalizowana odpytywaniem w wielu równoległych pętlach. Jednak zawsze istnieje zewnętrzny wyzwalacz, który rozpoczyna proces. Detektor zdarzeń nie jest funkcją, która nie zwraca wartości, ale funkcją, która czeka na ten zewnętrzny wyzwalacz przed jego uruchomieniem. Zamiast:
Myślę o tym jako:
a między
signal
następnym a następnym uruchomieniem modułu obsługi nie ma koncepcyjnego uruchamiania ani zapętlania kodu.źródło
forever: { select(); do stuff; }
, to za każdym razem ponownie bierzesz udział w wyścigu. Niezależnie od tego, czy robisz to wielokrotnie z jednego wątku, czy równolegle na osobnych wątkach lub procesorach, każde wydarzenie traktuję jak własną rasę. Na przykład przeglądarka internetowa to program wielowątkowy z wieloma pętlami zdarzeń w osobnych wątkach, co najmniej jeden dla interfejsu użytkownika i jeden dla każdej pobieranej strony. Pytanie, które zadaję przy kodowaniu, brzmi: „jak mogę przetwarzać zdarzenia wystarczająco szybko?” Czasami odpowiedzią jest pętla, czasem wątki, często kombinacja.Nie. To nie jest „zoptymalizowane odpytywanie”. Pętla zdarzeń wykorzystuje we / wy sterowane przerwaniami zamiast odpytywania.
Pętle While, Until, For itp. Są pętlami odpytywania.
„Odpytywanie” to proces wielokrotnego sprawdzania czegoś. Ponieważ kod pętli jest wykonywany w sposób ciągły, a ponieważ jest małą, „ciasną” pętlą, procesor ma mało czasu na przełączanie zadań i wykonywanie innych czynności. Niemal wszystkie „zawieszanie się”, „zawieszanie się”, „zawieszanie się” lub jakkolwiek chcesz to nazwać, gdy komputer przestaje odpowiadać, są przejawem zablokowania kodu w niezamierzonej pętli odpytywania. Oprzyrządowanie pokaże 100% użycia procesora.
Pętle zdarzeń sterowane przerwaniami są znacznie bardziej wydajne niż pętle odpytywania. Odpytywanie to wyjątkowo marnotrawstwo wykorzystania cykli procesora, dlatego dokładamy wszelkich starań, aby go wyeliminować lub zminimalizować.
Jednak, aby zoptymalizować jakość kodu, większość języków próbuje używać paradygmatu pętli odpytywania tak blisko, jak to możliwe, do poleceń obsługi zdarzeń, ponieważ służą one funkcjonalnie do podobnych celów w programie. Tak więc, ponieważ odpytywanie jest bardziej znanym sposobem oczekiwania na naciśnięcie klawisza lub coś takiego, niedoświadczonym łatwo jest go użyć i skończyć z programem, który sam może działać dobrze, ale nic innego nie działa podczas jego działania. „Przejął” maszynę.
Jak wyjaśniono w innych odpowiedziach, w przekazywaniu zdarzeń sterowanych przerwaniami zasadniczo „CPU” jest ustawiany w CPU, a proces jest „zawieszany” (nie wolno go uruchamiać), dopóki ta flaga nie zostanie zmieniona przez inny proces (taki jak klawiatura) sterownik zmienia go, gdy użytkownik naciśnie klawisz). Jeśli flaga jest faktycznym stanem sprzętowym, takim jak „podniesienie linii”, nazywa się to „przerwaniem” lub „przerwaniem sprzętowym”. Większość jednak jest zaimplementowana jako adres pamięci procesora lub pamięci głównej (RAM) i nazywa się je „semaforami”.
Semafory można zmieniać pod kontrolą oprogramowania, dzięki czemu mogą zapewnić bardzo szybki i prosty mechanizm sygnalizacji między procesami oprogramowania.
Przerwania można jednak zmienić tylko sprzętowo. Najbardziej powszechnym zastosowaniem przerwań jest wyzwalanie w regularnych odstępach czasu przez wewnętrzny układ zegarowy. Jednym z niezliczonych rodzajów akcji oprogramowania aktywowanych przez przerwania zegara jest zmiana semaforów.
Dużo pomijałem, ale musiałem gdzieś się zatrzymać. Zapytaj, czy potrzebujesz więcej szczegółów.
źródło
Zazwyczaj odpowiedzią jest sprzęt, system operacyjny i wątki w tle, nad którymi nie kontrolujesz konspiracji, aby wyglądało to na łatwe. Karta sieciowa odbiera niektóre dane, które wywołuje przerwanie, aby poinformować CPU. Obsługuje go program obsługi przerwań systemu operacyjnego. Następnie wątek w tle, którego nie kontrolujesz (który został utworzony przez zarejestrowanie się w wydarzeniu i śpi od momentu zarejestrowania się w nim) jest budzony przez system operacyjny w ramach obsługi zdarzenia i uruchamia procedurę obsługi zdarzenia.
źródło
Sprzeciwiam się wszystkim pozostałym odpowiedziom, które do tej pory widzę, i mówię „tak” . Myślę, że inne odpowiedzi zbyt komplikują sprawy. Z koncepcyjnego punktu widzenia wszystkie pętle zdarzeń są zasadniczo:
Jeśli próbujesz zrozumieć pętle zdarzeń po raz pierwszy, myślenie o nich jako o prostej pętli nie zaszkodzi. Niektóre podstawowe struktury czekają, aż system operacyjny dostarczy zdarzenie, a następnie kieruje je do jednego lub kilku modułów obsługi, a następnie czeka na następne zdarzenie i tak dalej. To naprawdę wszystko z punktu widzenia aplikacji.
źródło
Nie wszystkie wyzwalacze zdarzeń są obsługiwane w pętlach. Sposób, w jaki często piszę własne silniki zdarzeń, wyglądałby następująco:
Zauważ, że chociaż Memo 1 jest w pętli, pętla służy do powiadamiania każdego słuchacza. Sam wyzwalacz zdarzenia niekoniecznie jest zapętlony.
Teoretycznie kluczowe zdarzenia na poziomie systemu operacyjnego mogą korzystać z tej samej techniki (choć myślę, że zamiast tego często odpytują? Spekuluję tutaj), pod warunkiem, że system operacyjny udostępnia jakiś
registerListener
interfejs API.źródło