Portál AbcLinuxu, 18. říjen 2017 18:51

Paralelizace běžných činností v konzoli pomocí GNU Parallel

14. 7. 2014 | David Watzke
Články - Paralelizace běžných činností v konzoli pomocí GNU Parallel  

V dnešní době je většina počítačů schopná paralelního zpracování instrukcí a přesto stále existuje mnoho nástrojů, které toho nevyužívají. Pojďme si ukázat jak můžeme zrychlit různé běžné úkony, které provádíme v konzoli, pomocí GNU Parallel.

Program parallel je naprogramovaný v Perlu a je parádní zejména pro paralelizaci činnosti jiných nástrojů, které to implicitně nepodporují.

Než si budete jisti jak se parallel chová, doporučuji jej spouštět nejdřív s přepínačem --dry-run, který pouze vypíše jaké příkazy by byly spuštěny. V ukázkách jej neuvádím, tak si jej dle potřeby doplňte. Potom možná v některých případech budete chtít použít přepínač -v, aby parallel za běhu vypisoval příkazy, které spouští.

Například toto konvertuje všechny MP3 soubory na WAV rekurzivně vůči aktuálnímu adresáři:

find ./ -iname '*.mp3' -type f -print0 | parallel -0 -v -- lame --decode

V této ukázce find dodá seznam cest k MP3 souborům (kde jednotlivé cesty jsou odděleny speciálním znakem \0, který se v Linuxu jako jediný nesmí vyskytovat v cestě k souboru) na vstup programu parallel, kterému přepínačem -0 řekneme, aby použil jako oddělovač znak \0 (výchozí oddělovač je \n, tedy nový řádek, přičemž libovolný jiný oddělovač lze nastavit přepínačem --arg-sep). Potom (volitelně) explicitně ukončíme seznam přepínačů pomocí -- (čímž zajistíme, aby nebylo možné další argumenty zaměnit za přepínače programu – toto je velmi žádoucí používat ve skriptech, kde předem neznáte argumenty příkazu, neboť jsou např. složeny pomocí proměnných ze vstupů uživatele) a nakonec uvedeme příkaz, který se má nad jednotlivými soubory vykonat (zde lame --decode, jež převede zadanou MP3 na WAV).

Příkaz se spustí jednou pro každý soubor, a to paralelně v N instancích 1:1 dle počtů procesorových jader, kterými systém disponuje. Počet souběžných procesů lze ovlivnit přepínačem -j – tomuto přepínači můžete zadat celé číslo x pro uvedení počtu paralelně běžících procesů nebo případně číslo se znaménkem plus či mínus pro spuštění max. N+x nebo N-x paralelních procesů (kde N je počet jader a x je celočíselný argument se znaménkem).

Tohle byla triviální ukázka, kterou stejně tak dobře zvládnou nástroje xargs a xjobs, které dále v článku také představuji. Pojďme se podívat na zajímavější příklady.

Co třeba když potřebujeme „grepnout“ gigantický textový soubor na výskyt nějakého řetězce? Úložiště je rychlé (anebo je soubor nakešovaný), ale grep paralelně nepracuje – co s tím? Třeba toto:

parallel --pipe --block 20M -- grep --color=always substring < bigfile

V této ukázce parallel vezme data ze standardního vstupu (--pipe) a rozdělí je na bloky po 20 MB (--block 20M; delší řádky automaticky zvětší velikost bloku) a nad každým blokem se spustí instance programu grep (s přepínačem --color=always, který vynutí barevné odlišení odpovídajícího řetězce).

Tento přístup má své nevýhody, ale do jisté míry je možné je řešit. Například když chcete použít grep s přepínačem -n, abyste viděli na jakém řádku se hledaný text vyskytuje, tak s tímto postupem samozřejmě narazíte, protože každý blok má řádky číslované od 1. Řešením může být toto:

nl bigfile | parallel -k --pipe --block 20M -- grep --color=always substring

Pomocí nl (nebo alternativně lze použít cat -n) si na začátek každého řádku vypíšeme jeho pořadové číslo a pak ještě (volitelně) předáme programu parallel přepínač -k, který zajistí, aby se výstup vypisoval ve správném pořadí (v tomto případě po zpracování datových bloků od prvního k poslednímu, takže každé další číslo řádky s výskytem hledaného řetězce bude vyšší než to předchozí).

Pozor, tento trik s číslováním řádků mimo grep má jednu nevýhodu. Program nl zde samozřejmě musí soubor sekvenčně přečíst a zpracovat, takže soubor nelze jen tak přečíst z keše a bude to o něco pomalejší. Toto není zásadní problém, neboť tato operace je obecně výrazně rychlejší než hledání regulárního výrazu v textovém souboru, ale je dobré si to uvědomit. Zrovna tak je potřeba mít na paměti, že ne vždy toto paralelní spouštění grepu bude rychlejší než když jej spustíte jen tak, protože spouštění více instancí přidává navíc nějakou režii. Dle mých testů se vyplácí zapojit parallel až když hledáte nějaký netriviální regulární výraz.

Mimochodem, grep může být mnohem rychlejší, když mu nastavíte základní locale „C" místo nějaké UTF-8 locale jako je třeba “cs_CZ.UTF-8", ale samozřejmě je potřeba vždy zvážit, zda je tato změna žádoucí.

Nyní trochu odbočím: pokud vezmete ukázkový příkaz a nahradíte „substring“ za složitější výraz obsahující mezery anebo různé speciální znaky, tak zjistíte, že se to celé nechová tak, jak byste chtěli. Ukázka, která nebude fungovat:

nl bigfile | parallel -k --pipe --block 20M -- grep --color=always "substring test"

V tomto případě je potřeba předat nástroji parallel přepínač -q, který provede escapování znaků, které mají v shellu speciální význam. Správně je to tedy takto:

nl bigfile | parallel -qk --pipe --block 20M -- grep --color=always "substring test"

nebo alternativně příkaz spustit bez -q takto (escapování provádíme sami):

nl bigfile | parallel -k --pipe --block 20M -- grep --color=always '"substring test"'

Přepínač -q (--quote) není ve výchozím stavu aktivní, protože většinou to není potřeba a rozbíjí to jinou zajímavou funkcionalitu; například s -q není možné spustit něco jako:

ls *.gz | parallel -q "zcat {} | bzip2 > {.}.bz2"

Příkaz výše by bez -q vytvořil pro každý gzip archív v adresáři jiný archív typu bzip2 se stejným obsahem. Ovšem s -q toto není možné, protože mezery, znaky pipe | i znaky přesměrování > byly escapovány a vzniklý příkaz se nyní chová jako kdybyste ho do konzole zadali jako jeden dlouhý argument. Nedopadne to dobře. Nechceme-li tedy přijít o možnost spouštět takto komplexní příkazy, musíme se o escapování postarat sami.

V první ukázce jsem využil toho, že program lame automaticky vytvoří výstupní soubor pojmenovaný stejně jako vstupní, pouze korektně změní příponu. Toto vám jednak u všech programů neprojde a navíc ne vždy je to žádoucí, takže si ukažme jak se to dá řešit.

Vytvoříme všem JPEG obrázkům v aktuálním adresáři malý náhled pomocí nástroje convert z balíčku ImageMagick. Nejdřív pro jeho snadnost ukážu krátký zápis a potom teprve korektní zápis:

ls *.jpg | parallel convert -resize 25% '{}' '{.}-small.jpg'

nebo

parallel convert -resize 25% '{}' '{.}-small.jpg' ::: *.jpg

(Druhý příkaz je ukázkou toho, že parallel umí převzít seznam souborů i jako své argumenty, jen je potřeba je uvést za oddělovač :::.)

Opět příkazu parallel předáme seznam souborů ke zpracování. Na název souboru se můžeme odkázat pomocí řetězce {}, přičemž tento lze různými způsoby modifikovat, např. {.} vrátí vstupní až k poslední tečce (tzn. bez přípony).

Toto vám ve většině případů bude fungovat a asi bych to tak sám zapsal pro jednorázové zpracování, ale nedoporučoval bych to tímto způsobem spouštět ve skriptech. Je zde totiž několik problémů. Nahrazení *.jpg za seznam všech souborů, jejichž názvy končí na „.jpg“, provádí shell a nikoliv ls, takže když máte v aktuálním adresáři velmi mnoho takových souborů (anebo klidně málo, ale s velmi dlouhými názvy), tak vám ls klidně může vypsat chybu argument list too long. Další věc je, že nemáte jistotu, že se v seznamu neobjeví adresář – stačí když jeho název končí na „.jpg“ a v seznamu se objeví a budou tím pádem do zpracování zahrnuty i všechny soubory v tomto adresáři nezávisle na jejich příponě. A to stále není vše; soubory mohou v názvu obsahovat i znak nového řádku (lze vytvořit v bashi např. příkazem touch $'a\nb' a smazat pomocí rm -- $'a\nb' ), s čímž si příkaz výše také neporadí a bude brát část před novým řádkem a část za ním jako dva odlišné názvy souborů. Řešením je použít:

find ./ -maxdepth 1 -iname '*.jpg' -type f -print0 | parallel -0 -- convert '{}' '{.}-small.jpg'

Toto navíc jako bonus vyhledá soubory s příponou .jpg bez ohledu na velikost písmen (tzn. jako kdybychom výše napsali ls *.[jJ][pP][gG]).

Další základní vlastností je samozřejmě možnost paralelně spustit seznam příkazů zapsaných v souboru:

parallel < /tmp/command_list

anebo

parallel :::: /tmp/command_list

Jak je vidět, parallel umí přečíst seznam argumentů ze zadaného souboru i přímo, stačí jej uvést za čtyři dvojtečky (oproti třem dvojtečkám, když chcete uvádět argumenty přímo na příkazovém řádku, viz výše).

Někdy se vám možná stane, že budete chtít vidět seznam procesů, které má parallel spuštěné. Vypíše vám je, když mu pošlete signál SIGUSR1. Když si budete přát ukončit parallel, ale nepřerušovat již spuštěné procesy, pošlete mu signál SIGTERM a program nechá doběhnout to, co již spustil, a pak se ukončí.

Když si definujete funkci v bashi a budete ji chtít spouštět pomocí parallel, nezapomeňte ji neprve exportovat:

RePack() { zcat -- "$1" | bzip2 -9c > "${1%.*}.bz2" && rm -f -- "$1"; }
export -f RePack
parallel RePack ::: *.gz  # ve skriptech radši použijte find místo wildcard, viz výše

Než vás odkážu na velice obsáhlý manuál pro více příkladů, ukážu ještě jedno použití, které se mi líbí. Když nějaký program, který voláte přes parallel, umí zpracovat více argumentů najednou, můžete toho využít díky přepínači -X, který rozdělí seznam vstupů tak, aby se jich každé spouštěné instanci předalo co nejvíce a v případě potřeby je rovnoměrně rozdělí mezi zadaný počet instancí.

Takže pak můžete spustit něco jako:

parallel -j 8 -X oggenc ::: *.wav

Bude to fungovat podobně jako:

oggenc *.wav

ale s tím rozdílem, že parallel seznam souborů WAV rovnoměrně rozdělí mezi osm instancí oggenc.

Přepínačem -N lze shora omezit počet argumentů, které program dostane.

Pro více informací zkuste omrknout:

man 1 parallel
man 1 parallel_tutorial

Dozvíte se například to, že parallel umí distribuovat práci i na vzdálené počítače pomocí SSH tak, že tam nakopíruje soubory ke zpracování, paralelně je začne zpracovávat a každý výsledný soubor ihned zase přenese zpátky a uklidí po sobě na vzdálené straně. To se hodí, když máte mezi počítači velmi rychlou síť a váš stroj má pomalý procesor (anebo když třeba zcela postrádá požadovanou funkcionalitu).

parallel --sshlogin node01.lan --trc /tmp/{/.}.wav oggdec {} -o /tmp/{/.}.wav ::: *.ogg

Přepínač --trc je zkratkou --transfer (přenes na vzdálenou stranu), --return (výsledek nakopíruj zpět) a --cleanup (ukliď po sobě). Je potřeba mu dát jako argument šablonu názvu souboru, který se má zkopírovat zpátky ze vzdáleného serveru. Dodám, že {/.} je nahrazeno za název souboru bez cesty a bez přípony, tedy z cesty /home/test/soubor.txt vznikne podřetězec soubor, čehož jsem využil pro dodání vlastní cesty (/tmp) a vlastní přípony (.wav).

Podělte se prosím v diskuzi, pokud vás napadne nějaké pěkné využití programu, které jsem nezmínil.

Další články z této rubriky

Syncthing
Twibright Registrator: Instalace, odinstalace, test, základní použití
Twibright Registrator: fotografie v šeru bez stativu 2
Twibright Registrator: fotografie v šeru bez stativu 1
Filtrujeme čtivé texty z Projektu Gutenberg 9

Diskuse k tomuto článku

14.7.2014 14:00 pepa
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Diky, zas jsem se neco priucil... :)
15.7.2014 12:00 panika
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
super clanek, taky dekuju
16.7.2014 09:19 omg
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
hlavne se nauc priklady u --res prepinace.
David Watzke avatar 16.7.2014 09:49 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
To je dobrá připomínka - jde o užitečný přepínač, který jsem v článku nezmínil. Ukládá standardní a chybový výstup každého spouštěného příkazu. Osobně preferuju přístup, že si to uložím sám (dává mi to větší flexibilitu při volbě názvu výstupních souborů), ale určitě se to někdy může hodit.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
14.7.2014 22:44 jama
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Skoda ze ten grep nenalezne vyskyty vyrazu pokud jsou zrovna na nejake hranici bloku.

Rychly ale nepresny :).
14.7.2014 22:53 chrono
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Ak sa grep používa na jednotlivé riadky (a normálny grep nič iné ani nevie), tak žiadny problém nie je (pretože, ako to už bolo napísané v článku, parallel dá do bloku vždy celý riadok).
15.7.2014 00:20 ebik | skóre: 2
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
coz ma zase jine nevyhody - musi ten konec radku naijit, coz je operace, ktera trva zhruba tolik, jak jsou radky dlouhe (pokud je to napsano chytre)
Nuphar avatar 14.7.2014 23:00 Nuphar | skóre: 17
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Dost dobrý. Sice to asi budu trávit docela dlouho a budu si to muset ještě minimálně jednou přečíst, ale je to hodně dobré. :-) Díky.
Per aspera, Asparagus et Aspergillus ad a/Astra!
15.7.2014 09:04 pet
Rozbalit Rozbalit vše PŘEKLEP
Odpovědět | Sbalit | Link | Blokovat | Admin
parallel --sshlogin node01.lan --trc /tmp/{/.}.wav oggdec {} -o /tmp/{/.}.wav ::: *.ogg

Dodám, že {./} je nahrazeno za název ...
Takže {./} nebo {/.}?
David Watzke avatar 15.7.2014 09:44 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: PŘEKLEP
Je to {/.} - díky za upozornění, opravil jsem to v článku.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
16.7.2014 09:32 Olga
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
use Parallel::ForkManager;
16.7.2014 12:45 ebik | skóre: 2
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Super. Přesně tohle jsem si chtěl napsat, akorát jsem byl vždycky línej to v tu chvíli řešit.
19.7.2014 12:28 v.podzimek | skóre: 17
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Pěkné, s xargs už jsem se kolikrát dost natrápil, abych dosáhl svého. Bude se nám to hodit pro spoustění pylintu na zdrojácích Anacondy.
25.7.2014 09:36 Trubicoid2
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Jde nejak udelat ta funkce bez bashe, treba v dash? Tedy mam skript o vice radcich, co chci spustit na kazdy soubor
David Watzke avatar 25.7.2014 09:38 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
To nevím. Osobně bych vytvořil skript (ideálně takový, který je schopný zpracovat více vstupních argumentů najednou, aby se nemusel spouštět tolikrát).
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
29.7.2014 11:27 ebik | skóre: 2
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Vyexportovat funkce pro bash lze. Využívá to toho, že bash exportuje funkce jako obyčejné proměnné. Jen to nemá tak pěknou syntaxi:
#!/bin/dash

Pozdrav="() {
  echo ahoj;
}"
export Pozdrav
bash -c Pozdrav
Je otázka ale jaký shell použije ten příkaz parallel. (Dá se pak asi z parallel spustit "bash -c Funkce" ale to už začíná být dost přes ruku.
29.7.2014 10:04 nl + grep
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Odpovědět | Sbalit | Link | Blokovat | Admin
Dobrý článek, díky.

Trochu mě "tahá za oči" ten příklad s nl | grep. Já vím že vymyslet krátké příklady které dělají aspoň trochu něco smysluplného je problém, ale tohle podle mého názoru není použitelné:

Neměřil jsem to na reálných datech, ale podle mého názoru pokud už ten nl musí fakt ten soubor sekvenčně načíst, hledat \n a přidávat tam čísla řádků (= má data v cache procesoru), je už výrazně rychlejší na ta data rovnou pustit stavový automat pro ten hledaný regulární výraz. Řekl bych, že posíláním do roury a odtam do jiných procesů (a tedy přehazováním dat do cache jiných procesorů) se ztratí daleko víc času.

Tohle je přesně ten případ, kdy devět žen neodnosí jedno dítě za měsíc a 60 kopáčů nevykope metr hlubokou jámu za minutu.

-Yenya, http://www.fi.muni.cz/~kas/blog/
30.7.2014 00:04 Marek
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Taky mě to napadlo, ale je to popsané v článku: hodí se to až když je ten regulární výraz kurva-složitej (nebo rychlej disk nebo pomalej (i ne-vícevláknovej) procesor (nebo kombinace předešlých)).

První program dokončí svoji práci celkem rychle a pošle výstup druhému programu (grep), pak okamžitě může dál pokračovat v práci a předat druhý výstup další instanci grepu. Kdežto konvenční způsob by byl synchronní grep v jednom vláknu.

Marek
30.7.2014 13:31 nl + grep
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Složitý regulární výraz je tak jediná možnost, ovšem dost málo pravděpodobná. Délka vstupu bude omezená (vzhledem k tomu, že se bavíme o číslování řádků a tedy o RE, který ma matchovat jen v rámci řádku). Samozřejmě lze vymyslet patologický případ využívající například vnořené backreference nebo něco podobného, co by neumožnilo převést ten regulární výraz do konečného automatu. No ale článek samotný mluví dokonce jen o hledání substringu, což dost jistě odpovídá tomu co píšu - paralelizace je zde kontraproduktivní.

Rychlý disk neudělá žádný rozdíl (resp. s pomalým není už vůbec žádný důvod paralelizovat).

Pomalý procesor taky neudělá žádný rozdíl. V obou těchto případech nejde o rychlost ale o to, že je daleko dražší (ale fakt hodně!) zbavovat se dat, které už mám v cachi procesoru a posílat je jinému procesoru k tomu, aby s nimi něco udělal. To bychom leda museli uvažovat o procesoru bez cache :-) nebo o řádcích vstupu, které se nevejdou ani do sekundární cache procesoru (dnes řádově megabajty).

Právěže není vůbec pravda, že by první program (nl) dokončil svou práci výrazně rychleji než třeba grep tak, aby vůbec mělo cenu uvažovat o tom tu práci rozdělit mezi víc procesů. Fakt si to zkuste.

Ostatně tohoto triku "když už mám data v cache CPU, udělám s nimi co nejvíc výpočtů naráz" se využívá fakt hodně dlouho. Vizte třeba funkci copy_and_csum() v kernelu Linuxu tak 15 let zpátky - bylo daleko rychlejší zkopírovat síťový packet na místo určení a u toho zároveň počítat/kontrolovat kontrolní součet, než tyto věci dělat odděleně.

-Yenya, http://www.fi.muni.cz/~kas/blog/
30.7.2014 14:33 nl + grep
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Schválně si zkuste:
cd /var/tmp
wget http://ftp.linux.cz/pub/FILES.byname    # textovy soubor cca 1.1 GB
for i in `seq 1 20` ; do time sh -c 'grep -n jezek FILES.byname >/dev/null'; done
for i in `seq 1 20` ; do time sh -c 'nl FILES.byname | grep jezek >/dev/null'; done
U mě první varianta běží cca 1.9 s reálného času (okolo 1.1 user, 0.8 system), druhá varianta 6.6 s reálného času (7.0 user, 1.5 system). Beru vždy nejrychlejší čas z těch 20 pokusů.

Nicméně zdá se, že samotný výpočet nad daty z cache taky není úplně zadarmo - když spustím ten první případ bez -n (bez počítání čísel řádků), tak je to ještě o dalších 0.2 s rychlejší.

-Yenya
David Watzke avatar 30.7.2014 13:54 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Souhlasím, že tenhle příklad se mi moc nepovedl, ale aspoň jsem se snažil vysvětlit, proč se to nehodí vždy (i když jsi mě mnohem rozsáhleji a přesněji doplnil a za to děkuju). Napadá tě lepší příklad?

Podle mě by bylo dobrý, kdyby parallel podporoval paralelní čtení z jednoho souboru - že by každý proces četl od jiného offsetu nějakou danou velikost, ale to by šlo samozřejmě jen tehdy, kdyby se nemusely hlídat konce řádků a práce by se rozdělovala dle fixní velikosti.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
30.7.2014 14:42 Yenya
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Nojo, když to není o podpoře v parallel, ale v těch spouštěných programech, které typicky čtou soubor dokud to jde (do konce souboru).

Napadlo mě, že to by asi parallel musel LD_PRELOADovat něco, co by při pokusu o čtení určitého souboru nad nějakou mez vracelo konec souboru. Jakože by každému potomkovi otevřel ten stejný soubor, zavolal lseek() na patřičný offset, a pak by ten deskriptor předal třeba jako std. vstup, a přes LD_PRELOAD by zamezil čtení za tu část souboru, která patří tomu konkrétnímu potomkovi.

No ale problém čísel řádků to neřeší.

Lepší příklad mě nenapadá.

-Yenya
David Watzke avatar 30.7.2014 14:53 David Watzke | skóre: 74 | blog: Blog... | Praha
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Já jsem to myslel trochu jinak. Ty soubory ke zpracování bys zadal jako argumenty přímo tomu parallel a volaným programům by se pak chunky předávaly třeba na vstup nebo přes pojmenovanou rouru, atd.
“Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
31.7.2014 08:57 ebik | skóre: 2
Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
Jo, jenže předání chunku přes rouru znamená v jednom programu (parallel) ten chunk načíst, pak* zapsat do roury, která zkopíruje data do adresního prostoru druhého programu (včetně kopírování přes nějaké kernel buffery mezi). To potom ten parallel klidně může číst vstup sekvenčně a schovávat si data někde v paměti.

*) trochu jsem to zjednodušil. Na linuxu myslím lze pomocí speciálních volání poslat data ze souboru do roury přímo, bez načítání do programu. Pořád tam je ale roura navíc, takže ze souborových cachí jdou data do bufferu roury a pak teprve do programu.

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.