“R” jak “równoległy”

https://xpil.eu/y8y

Natknąłem się ostatnio na artykuł o linuksowej aplikacji parallel. "Aplikacja" to może zbyt rozbujałe określenie - parallel to po prostu skrypt w Perlu. W dodatku w jakiejś dość leciwej wersji Perla, ponieważ założenie jest takie, że ma działać nawet na starszych komputerach / systemach, a przecież nie wszyscy używają najnowszego Perla 6.

Cóż to za zwierz?

Z założenia - dość prosty (to znaczy prosty z punktu widzenia użytkownika - kod źródłowy to ponad 11 tysięcy linii kodu). Umożliwia równoległe wykonywanie wielu kopii ("instancji") tego samego polecenia linuksowego, z różnymi parametrami dla każdej instancji.

Wyobraźmy sobie na przykład, że chcemy szybko sprawdzić które adresy IP w naszej sieci lokalnej odpowiadają na polecenie ping. Standardowo zrobilibyśmy to na przykład tak:

for i in $(seq 1 254); do ping -c 1 192.168.1.$i; done

Na wyjściu dostaniemy całkiem sporo śmiecia wygenerowanego przez komendę ping, które potem możemy odfiltrować, przekształcić i tak dalej. Kupa roboty, ale do ogarnięcia. Problem jednak polega na tym, że każde wywołanie ping czeka na zakończenie poprzedniego, i trwa całkiem długo jeżeli dany adres IP nie odpowiada. Taka pętla po 254 adresach zajmie - w najgorszym razie - ponad 4 minuty. Można oczywiście skrócić maksymalny czas oczekiwania polecenia ping, ale ma to swoje wady (ustawiając za krótki czas oczekiwania ryzykujemy fałszywymi odrzuceniami).

Zamiast tego można skorzystać z polecenia parallel, które - podobnie jak w przykładzie powyżej - wykona komendę ping 254 razy, ale - w odróżnieniu od przykładu powyżej - wszystkie te wykonania będą uruchomione "równocześnie".

(cudzysłów zamierzony - w naszym Kosmosie idea "równoczesności" nie działa - ale na potrzeby tego wpisu uznajmy, że "równocześnie" oznacza "wystarczająco równocześnie, żeby nam się wydawało, że jest faktycznie równocześnie")

Polecenie będzie wyglądać, na przykład, o tak:

seq -w 1 254 | parallel -j 0 'ping -w 1 -c 1 192.168.1.{} > /dev/null && echo 192.168.1.{}' 2>/dev/null

Na wyjściu dostaniemy listę adresów IP, które odpowiedziały na polecenie ping, ale zamiast czekać 254 sekundy, poczekamy maksymalnie, 4-5 sekund, może ciut więcej.

Profity:

  • Krótszy czas oczekiwania
  • Nie musimy babrać się z "zaśmieconym" wyjściem komendy ping z pierwszego przykładu.

O ile ten drugi profit jest sztuczny, ponieważ tricku z /dev/null i przekierowaniem błędów moglibyśmy też użyć w pierwszym przykładzie, o tyle zrównoleglenie operacji jest nie do przecenienia.

Jeżeli ktoś się zastanawia co oznacza parametr -j 0 (który nawiasem mówiąc można też zapisać bez spacji, czyli -j0) to spieszę wyjaśnić, że chodzi o maksymalną liczbę równoległych operacji - jeżeli damy tam jakąś liczbę dodatnią, to maksymalnie tyle procesorów (rdzeni? wątków? chyba wątków) będzie używanych do zrównoleglenia pracy. Jeżeli zaś damy zero (jak powyżej), to parallel spróbuje uruchomić ile wlezie. Czyli w moim przypadku 16 (8 rdzeni, HT). 16 wątków oznacza, że nawet jeżeli żaden z 253 adresów IP nie odpowie, to będziemy czekać maksymalnie około 4-5 sekund. W wersji z pętlą for poczekamy natomiast dobrze ponad 4 minuty.

Pomysł na dzisiejszy wpis wziąłem z Hacker News, natomiast przykład z poleceniem ping ściągnąłem z dokumentacji parallel (trochę go uprościłem).

Ten wpis pokazuje zaledwie drobny ułamek możliwości parallel. Skrypt ten potrafi dużo więcej, na przykład podłączyć się do zdalnego systemu i uruchomić tam polecenie (w trybie równoległym) i zwrócić wyniki lokalnie. I kupę innych rzeczy.

Wady?

Perl jest wolny - przy czym używam pojęcia "wolny" w kontekście OS-u, a nie użytkownika końcowego. Na każde rozpoczęte równoległe zadanie trzeba przyjąć narzut kilku - kilkunastu milisekund. Niezauważalne dla galarety między naszymi uszami, ale przy poważniejszych / trudniejszych zadaniach może mieć widoczny wpływ.

https://xpil.eu/y8y

1 Comment

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.