2016-01-05 9 views
5

Niedawno zacząłem pisać trochę kodu C++, który używa gniazd, które chciałbym być asynchroniczne. Czytałem wiele postów o tym, jak można używać ankiet i wybierz, aby moje asynchroniczne gniazda (za pomocą ankiety lub wybierz, aby czekać na bufor wysyłania lub recv), ale na mojej stronie serwera mam tablicę struct pollfd, gdzie za każdym razem gniazdo nasłuchu akceptuje połączenie, dodaje je do tablicy struct pollfd, dzięki czemu może monitorować recv (POLLIN) gniazda.Czy istnieje lepszy sposób korzystania z asynchronicznych gniazd TCP w C++ zamiast ankiety lub wyboru?

Mój problem polega na tym, że gdybym miał 5000 gniazd połączonych z moim gniazdem nasłuchującym na moim serwerze, to tablica struktury pollfd miałaby rozmiar 5000, ponieważ monitorowałaby wszystkie podłączone gniazda, ALE jedyny sposób, jaki znam aby sprawdzić, czy recv dla gniazda jest gotowy, to poprzez zapętlenie wszystkich elementów w tablicy struct pollfd, aby znaleźć te, których revents równa się POLLIN. To wydaje się po prostu mało wydajne, gdy liczba podłączonych gniazd jest bardzo duża. Czy jest lepszy sposób to zrobić?

W jaki sposób biblioteka boost :: asio obsługuje async_accept, async_send, etc ...? Jak mam sobie z tym poradzić?

+0

Nie ma * boost * w [tag: c], należy zachować ostrożność przy wyborze tagów. –

+4

Miksujesz "nieblokujące" i "asynchroniczne". Są to różne tryby. 'select()' i przyjaciele służą do niezablokowania operacji we/wy. Brzmi to tak, jakbyś potrzebował asynchronicznego I/O, w takim przypadku powinieneś użyć 'boost' lub przełączyć się na inny język, taki jak Java, który ma wbudowaną asynchronię. Ale tylko dla 5000 klientów nie powinieneś przeoczyć blokowania I/O z wątkami. – EJP

+0

@EJP ... lub rozważ użycie ['std :: async()'] (http: //www.cplusplus.com/reference/future/async /) – Christophe

Odpowiedz

2

Co do cholery, napiszę odpowiedź.

Mam zamiar zignorować terminologię "asynchroniczną" a "nieblokującą", ponieważ uważam, że nie ma to znaczenia dla twojego pytania.

Martwisz się wydajnością podczas pracy z tysiącami klientów sieciowych i masz rację. Znów odkryłeś C10K problem. Kiedy sieć była młoda, ludzie widzieli potrzebę niewielkiej liczby szybkich serwerów do obsługi dużej liczby (względnie) wolnych klientów. Istniejące interfejsy typu select/poll wymagają skanowania liniowego - zarówno w jądrze, jak iw przestrzeni użytkownika - we wszystkich gniazdach, aby określić, które są gotowe. Jeśli wiele gniazd jest często bezczynnych, twój serwer może skończyć spędzać więcej czasu na zastanawianiu się, co robić, niż wykonywać rzeczywistą pracę.

Przewijanie do przodu do dziś, gdzie mamy dwa podejścia do radzenia sobie z tym problemem:

1) Za pomocą jednego wątku na gniazdo i blokowanie tylko kwestia odczytuje i zapisuje. Zwykle jest to najprostszy kod, moim zdaniem, a nowoczesne systemy operacyjne są dość dobre, pozwalając bezczynnym wątkom spać spokojnie na uboczu, bez nakładania znaczących kosztów ogólnych. Z mojego doświadczenia wynika, że ​​takie podejście sprawdza się bardzo dobrze w przypadku setek klientów; Nie mogę osobiście powiedzieć, jak to zadziała dla tysięcy osób.

2) Użyj jednego z interfejsów specyficznych dla platformy, które zostały wprowadzone w celu rozwiązania problemu C10K. Oznacza to epoll (Linux), kqueue (BSD/Mac) lub porty zakończenia (Windows). (Jeśli uważasz, że epoll jest taka sama jak poll, spójrz jeszcze raz.) Wszystkie z nich powiadomią twoją aplikację tylko o gniazdach, które są rzeczywiście gotowe, unikając marnotrawnego skanowania liniowego przez nieużywane połączenia. Istnieje kilka bibliotek, które ułatwiają korzystanie z tych interfejsów dla platformy, w tym libevent, libev i Boost.Asio. Przekonasz się, że wszystkie z nich w ostateczności odwołują się do epoli w Linuksie, kina na BSD i tak dalej, kiedykolwiek takie interfejsy są dostępne.

+0

Mamy w zasadzie * trzy * podejścia: dwa wspomniane i asynchroniczne operacje we/wy. – EJP

+0

@EJP: Na niskim poziomie, twoje "asynchroniczne operacje we/wy" są prawdopodobnie zbudowane na jednym z tych dwóch. (Boost.Asio na pewno jest, na przykład.) Chociaż może nie rozumiem twojego użycia tego terminu. Nawiasem mówiąc, Wikipedia definiuje "asynchroniczne operacje we/wy" jako synonim "nieblokujących operacji we/wy" (https://en.wikipedia.org/wiki/Asynchronous_I/O), a następnie podaje opis, który ma nic wspólnego z tym pytaniem lub moją odpowiedzią. – Nemo

Powiązane problemy