Wydajność IPC: nazwana rura a gniazdo


114

Wydaje się, że wszyscy mówią, że nazwane potoki są szybsze niż gniazda IPC. O ile są szybsze? Wolałbym używać gniazd, ponieważ mogą one komunikować się w dwie strony i są bardzo elastyczne, ale wybiorą prędkość zamiast elastyczności, jeśli jest to znaczna ilość.


10
Twój przebieg będzie się różnić. :) Profil typowe zastosowanie dla zamierzonej aplikacji i wybierz lepsze z dwóch. Następnie profiluj anonimowe potoki, gniazda innych domen i rodzin, semafory i pamięć współdzieloną lub kolejki komunikatów (SysV i POSIX), sygnały czasu rzeczywistego ze słowem danych lub cokolwiek innego. pipe(2)(hm,? mkfifo(3)) może być zwycięzcą, ale nie dowiesz się, dopóki nie spróbujesz.
pilcrow

2
Kolejki komunikatów SysV FTW! Nie mam pojęcia, czy są szybkie, po prostu mam do nich słabość.
Tom Anderson,

4
Co to jest „prędkość” w tym przypadku? Ogólna szybkość przesyłania danych? Lub opóźnienie (jak szybko pierwszy bajt dociera do odbiornika)? Jeśli chcesz szybkiego lokalnego przesyłania danych, trudno jest pokonać pamięć współdzieloną. Jeśli jednak problemem jest opóźnienie, to pytanie staje się bardziej interesujące ...
Ian Ni-Lewis

Odpowiedzi:


64

Sugerowałbym, abyś najpierw wybrał łatwą ścieżkę, ostrożnie izolując mechanizm IPC, abyś mógł zmienić gniazdo na rurę, ale zdecydowanie najpierw wybrałbym gniazdo. Powinieneś być pewien, że wydajność IPC jest problemem przed prewencyjną optymalizacją.

A jeśli wpadniesz w kłopoty z powodu szybkości IPC, myślę, że powinieneś rozważyć przejście na pamięć współdzieloną zamiast używania potoku.

Jeśli chcesz przetestować szybkość transferu, powinieneś wypróbować socat , który jest bardzo wszechstronnym programem, który pozwala stworzyć prawie każdy rodzaj tunelu.


48

Najlepsze wyniki, jakie uzyskasz dzięki rozwiązaniu Shared Memory .

Nazwane potoki są tylko o 16% lepsze niż gniazda TCP .

Wyniki uzyskano dzięki benchmarkingowi IPC :

  • System: Linux (Linux ubuntu 4.4.0 x86_64 i7-6700K 4,00 GHz)
  • Wiadomość: 128 bajtów
  • Liczba wiadomości: 1000000

Wzorzec dla rur:

Message size:       128
Message count:      1000000
Total duration:     27367.454 ms
Average duration:   27.319 us
Minimum duration:   5.888 us
Maximum duration:   15763.712 us
Standard deviation: 26.664 us
Message rate:       36539 msg/s

Test porównawczy FIFO (nazwanych potoków):

Message size:       128
Message count:      1000000
Total duration:     38100.093 ms
Average duration:   38.025 us
Minimum duration:   6.656 us
Maximum duration:   27415.040 us
Standard deviation: 91.614 us
Message rate:       26246 msg/s

Test porównawczy kolejki wiadomości:

Message size:       128
Message count:      1000000
Total duration:     14723.159 ms
Average duration:   14.675 us
Minimum duration:   3.840 us
Maximum duration:   17437.184 us
Standard deviation: 53.615 us
Message rate:       67920 msg/s

Test porównawczy pamięci współdzielonej:

Message size:       128
Message count:      1000000
Total duration:     261.650 ms
Average duration:   0.238 us
Minimum duration:   0.000 us
Maximum duration:   10092.032 us
Standard deviation: 22.095 us
Message rate:       3821893 msg/s

Test gniazd TCP:

Message size:       128
Message count:      1000000
Total duration:     44477.257 ms
Average duration:   44.391 us
Minimum duration:   11.520 us
Maximum duration:   15863.296 us
Standard deviation: 44.905 us
Message rate:       22483 msg/s

Test porównawczy gniazd domeny Unix:

Message size:       128
Message count:      1000000
Total duration:     24579.846 ms
Average duration:   24.531 us
Minimum duration:   2.560 us
Maximum duration:   15932.928 us
Standard deviation: 37.854 us
Message rate:       40683 msg/s

Benchmark ZeroMQ:

Message size:       128
Message count:      1000000
Total duration:     64872.327 ms
Average duration:   64.808 us
Minimum duration:   23.552 us
Maximum duration:   16443.392 us
Standard deviation: 133.483 us
Message rate:       15414 msg/s

1
Dzięki za szczegółowe testy porównawcze. Czy masz na myśli „multiprocessing.Queue” z „Message Queue”?
ovunccetin

1
Kolejka wiadomości to systemowa kolejka komunikatów XSI ( man7.org/linux/man-pages/man0/sys_msg.h.0p.html )
chronoxor

34

Zgodzę się z shodanex, wygląda na to, że przedwcześnie próbujesz zoptymalizować coś, co nie jest jeszcze problematyczne. Jeśli nie wiesz , że gniazdka będą wąskim gardłem, po prostu ich użyję.

Wiele osób, które przysięgają na nazwane potoki, znajduje niewielkie oszczędności (w zależności od tego, jak dobrze wszystko inne zostało napisane), ale kończy z kodem, który spędza więcej czasu na blokowaniu odpowiedzi IPC niż na wykonywaniu pożytecznej pracy. Oczywiście, pomagają w tym schematy nieblokujące, ale mogą być trudne. Spędzając lata na wprowadzaniu starego kodu do współczesności, mogę powiedzieć, że w większości przypadków przyspieszenie jest prawie zerowe.

Jeśli naprawdę myślisz, że gniazda spowalniają cię, wyjdź z bramki, korzystając z pamięci współdzielonej, zwracając szczególną uwagę na to, jak używasz zamków. Ponownie, w rzeczywistości możesz znaleźć małe przyspieszenie, ale zauważ, że marnujesz jego część, czekając na blokady wzajemnego wykluczania. Nie zamierzam popierać podróży do piekła futexu (cóż, już nie całkiem piekło w 2015 roku, w zależności od twojego doświadczenia).

Funt za funt, gniazda są (prawie) zawsze najlepszym sposobem na IPC w przestrzeni użytkownika w ramach monolitycznego jądra .. i (zwykle) najłatwiejszym do debugowania i utrzymania.


2
być może pewnego dnia w odległej utopijnej przyszłości będziemy mieli zupełnie nowe, modułowe, nowoczesne jądro, które domyślnie oferuje wszystkie (międzyprocesowe i inne) możliwości, które obecnie przechodzimy po potłuczonym szkle, aby osiągnąć ... ale hej ... można marzyć
Gukki5

27

Należy pamiętać, że gniazda niekoniecznie oznaczają IP (i TCP lub UDP). Możesz także użyć gniazd UNIX (PF_UNIX), które oferują zauważalną poprawę wydajności w porównaniu z połączeniem z 127.0.0.1


1
A co z systemem Windows?
Pacerier

1
@Pacerier Niestety nie można tworzyć gniazd lokalnych w systemie Windows w taki sam sposób, jak abstrakcyjnej przestrzeni nazw w systemie UNIX. Zauważyłem, że gniazda PF_UNIX są znacznie szybsze (> 10%) niż większość innych metod opisanych na tej stronie.
EntangledLoops

1
devblogs.microsoft.com/commandline/af_unix-come-to-windows aktualizacja, gniazda Unix są już dostępne w systemie Windows 10.
eri0o


11

Jeśli nie potrzebujesz szybkości, najprostszym rozwiązaniem są gniazda!

Jeśli patrzysz na szybkość, najszybszym rozwiązaniem jest pamięć współdzielona, ​​a nie nazwane potoki.


8

W przypadku komunikacji dwukierunkowej z nazwanymi potokami:

  • Jeśli masz kilka procesów, możesz otworzyć dwie potoki dla dwóch kierunków (procesA2ProcessB i processB2ProcessA)
  • Jeśli masz wiele procesów, możesz otwierać i usuwać potoki dla każdego procesu (processAin, processAout, processBin, processBout, processCin, processCout itp.)
  • Lub możesz jak zwykle przejść na hybrydę :)

Nazwane potoki są dość łatwe do zaimplementowania.

Np. Zaimplementowałem projekt w C z nazwanymi potokami, dzięki standardowej komunikacji opartej na plikach wejściowych i wyjściowych (fopen, fprintf, fscanf ...) był tak łatwy i czysty (jeśli to również się zastanawia).

Zakodowałem je nawet w Javie (serializowałem i wysyłałem przez nie obiekty!)

Nazwane potoki mają jedną wadę:

  • nie skalują się na wielu komputerach, takich jak gniazda, ponieważ polegają na systemie plików (zakładając, że współdzielony system plików nie jest opcją)

8

Jeden problem z gniazdami polega na tym, że nie mają one sposobu na opróżnienie bufora. Jest coś, co nazywa się algorytmem Nagle, który zbiera wszystkie dane i opróżnia je po 40 ms. Więc jeśli jest to responsywność, a nie przepustowość, może być lepiej z potokiem.

Możesz wyłączyć Nagle za pomocą opcji gniazda TCP_NODELAY, ale wtedy koniec odczytu nigdy nie otrzyma dwóch krótkich wiadomości w jednym wywołaniu odczytu.

Więc przetestuj to, skończyłem bez tego i zaimplementowałem kolejki oparte na mapowaniu pamięci z muteksem pthread i semaforem w pamięci współdzielonej, unikając wielu wywołań systemowych jądra (ale dziś nie są już one zbyt wolne).


3
„Więc przetestuj to” <- słowa, według których warto żyć.
Koshinae

6

Nazwane rury i gniazda nie są funkcjonalnie równoważne; gniazda zapewniają więcej funkcji (na początek są dwukierunkowe).

Nie możemy powiedzieć, która będzie działać lepiej, ale podejrzewam, że to nie ma znaczenia.

Gniazda domeny uniksowej będą robić prawie to samo, co gniazda tcp, ale tylko na komputerze lokalnym iz (być może trochę) mniejszym narzutem.

Jeśli gniazdo Unix nie jest wystarczająco szybkie i przesyłasz dużo danych, rozważ użycie pamięci współdzielonej między klientem a serwerem (co jest DUŻO bardziej skomplikowane w konfiguracji).

Unix i NT mają „nazwane potoki”, ale mają zupełnie inny zestaw funkcji.


1
Cóż, jeśli otworzysz 2 rury, uzyskasz również zachowanie bidi.
Pacerier

4

Możesz użyć lekkiego rozwiązania, takiego jak ZeroMQ [ zmq / 0mq ]. Jest bardzo łatwy w użyciu i znacznie szybszy niż gniazda.


2
Może ci się spodobać, zgadnij, Amit, następna grafika Martina SUSTRIKA - zgodna z POSIX nanomsg. W każdym razie witaj i ciesz się tym wspaniałym miejscem i zostań jego aktywnym członkiem.
user3666197
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.