2010-05-06 15 views
5

Projektuję pętlę zdarzeń dla asynchronicznego gniazda IO przy użyciu epoll/devpoll/kqueue/poll/select (w tym windows-select).Asynchroniczne projektowanie pętli zdarzeń i problemy

mam dwie możliwości wykonywania operacji, IO:

tryb

non-blocking, badanie na EAGAIN

  1. zestaw gniazdo w trybie non-blocking.
  2. Odczyt/zapis do gniazda.
  3. Jeśli operacja powiedzie się, po zakończeniu powiadomienia do pętli zdarzeń.
  4. Jeśli otrzymam EAGAIN, dodaj gniazdo do "wybierz listę" i gniazdo ankiety.

Tryb Polling: ankieta, a następnie wykonać

  1. gniazdo Dodaj do listy wybrać i sondować go.
  2. czekają na powiadomienie, że jest czytelny zapisu
  3. odczytu/zapisu
  4. postu powiadomienie o zakończeniu do pętli zdarzeń sucseeds

Dla mnie to wygląda jak pierwszy wymagałoby mniej wywołań systemowych podczas korzystania w trybie normalnym , specjalnie do pisania do gniazda (bufory są dość duże). Wygląda również na to, że można zmniejszyć narzut na liczbę "wybierz" egzekucji, szczególnie dobrze jest, gdy nie masz czegoś, co dobrze skaluje jako epoll/devpoll/kqueue.

Pytania:

  • czy są jakieś zalety drugim podejściu?
  • Czy występują problemy z przenośnością w przypadku nieblokujących operacji na gniazdach/deskryptorach plików w wielu systemach operacyjnych: Linux, FreeBSD, Solaris, MacOSX, Windows.

Uwagi: Proszę nie sugerować przy użyciu istniejących wdrożeń zdarzenie pętli/Gniazdo api

Odpowiedz

3

nie jestem pewien, że jest jakiś problem cross-platform; co najwyżej musiałbyś używać Windows Sockets API, ale z tymi samymi wynikami.

W przeciwnym razie wydaje się, że odpytujesz w obu przypadkach (unikając blokowania), więc oba podejścia są w porządku. Dopóki nie ustawisz się w pozycji do zablokowania (np. Gdy nie ma danych, napisz, gdy bufor jest pełny), nie ma żadnej różnicy.

Być może pierwsze podejście jest łatwiejsze do zakodowania/zrozumienia; więc idź z tym.

Może zainteresować Cię dokumentacja libev i c10k problem z interesującymi pomysłami/podejściami na ten temat.

2

Pierwszy projekt jest Proactor Pattern, drugi jest Reactor Pattern

Jedną z zalet jest to, że wzór reaktora można zaprojektować API, tak że nie trzeba przeznaczyć odczytu buforów dopóki dane są faktycznie tam do przeczytania. Zmniejsza to zużycie pamięci podczas oczekiwania na wejścia/wyjścia.

+0

Nie widzę powodu, dla którego nie można czekać na przydzielenie pamięci konieczne było zastosowanie pierwszego podejścia. Czy czegoś brakuje? – Ioan

+2

Przypuszczam, że tak, ale w praktyce nie jest to realizowane w ten sposób. W pierwszym przypadku potrzebujesz bufora dostępnego w krokach 2-4, w drugim potrzebujesz go tylko w kroku 3. – karunski

1

z mojego doświadczenia z niską latencję gniazdowych Apps:

do zapisów - spróbuj napisać bezpośrednio do gniazdka z pisania wątek (trzeba uzyskać muteksu pętli zdarzeń dla tego), jeśli zapis jest niekompletny subskrybować napisać gotowość z pętlą zdarzeń (wybierz/waitformultipleobjects) i zapisz z wątku pętli zdarzeń, gdy gniazdo będzie zapisywalne

dla odczytów - bądź zawsze "zasubskrybowany" dla gotowości do odczytu dla wszystkich gniazd, więc zawsze czytasz z wewnątrz pętli zdarzenia, gdy gniazdo zostanie odebrane czytelny