abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 17:11 | Nová verze

    Byl vydán Nextcloud Hub 8. Představení novinek tohoto open source cloudového řešení také na YouTube. Vypíchnout lze Nextcloud AI Assistant 2.0.

    Ladislav Hagara | Komentářů: 0
    dnes 13:33 | Nová verze

    Vyšlo Pharo 12.0, programovací jazyk a vývojové prostředí s řadou pokročilých vlastností. Krom tradiční nadílky oprav přináší nový systém správy ladících bodů, nový způsob definice tříd, prostor pro objekty, které nemusí procházet GC a mnoho dalšího.

    Pavel Křivánek | Komentářů: 4
    dnes 04:55 | Zajímavý software

    Microsoft zveřejnil na GitHubu zdrojové kódy MS-DOSu 4.0 pod licencí MIT. Ve stejném repozitáři se nacházejí i před lety zveřejněné zdrojové k kódy MS-DOSu 1.25 a 2.0.

    Ladislav Hagara | Komentářů: 30
    včera 17:33 | Nová verze

    Canonical vydal (email, blog, YouTube) Ubuntu 24.04 LTS Noble Numbat. Přehled novinek v poznámkách k vydání a také příspěvcích na blogu: novinky v desktopu a novinky v bezpečnosti. Vydány byly také oficiální deriváty Edubuntu, Kubuntu, Lubuntu, Ubuntu Budgie, Ubuntu Cinnamon, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Unity a Xubuntu. Jedná se o 10. LTS verzi.

    Ladislav Hagara | Komentářů: 13
    včera 14:22 | Komunita

    Na YouTube je k dispozici videozáznam z včerejšího Czech Open Source Policy Forum 2024.

    Ladislav Hagara | Komentářů: 2
    včera 13:22 | Nová verze

    Fossil (Wikipedie) byl vydán ve verzi 2.24. Jedná se o distribuovaný systém správy verzí propojený se správou chyb, wiki stránek a blogů s integrovaným webovým rozhraním. Vše běží z jednoho jediného spustitelného souboru a uloženo je v SQLite databázi.

    Ladislav Hagara | Komentářů: 0
    včera 12:44 | Nová verze

    Byla vydána nová stabilní verze 6.7 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 124. Přehled novinek i s náhledy v příspěvku na blogu. Vypíchnout lze Spořič paměti (Memory Saver) automaticky hibernující karty, které nebyly nějakou dobu používány nebo vylepšené Odběry (Feed Reader).

    Ladislav Hagara | Komentářů: 0
    včera 04:55 | Nová verze

    OpenJS Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 22 otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). V říjnu se verze 22 stane novou aktivní LTS verzí. Podpora je plánována do dubna 2027.

    Ladislav Hagara | Komentářů: 0
    včera 04:22 | Nová verze

    Byla vydána verze 8.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a v informačním videu. Zdůrazněn je průvodce migrací hostů z VMware ESXi do Proxmoxu.

    Ladislav Hagara | Komentářů: 0
    včera 04:11 | Nová verze

    R (Wikipedie), programovací jazyk a prostředí určené pro statistickou analýzu dat a jejich grafické zobrazení, bylo vydáno ve verzi 4.4.0. Její kódové jméno je Puppy Cup.

    Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (73%)
     (9%)
     (2%)
     (16%)
    Celkem 796 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

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

    14. 7. 2014 | David Watzke | Návody | Systém | 13988×

    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.

           

    Hodnocení: 100 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Diskuse byla administrátory uzamčena

    14.7.2014 14:00 pepa
    Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
    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.
    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
    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)
    14.7.2014 23:00 Nuphar | skóre: 18
    Rozbalit Rozbalit vše Re: Paralelizace běžných činností v konzoli pomocí GNU Parallel
    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
    parallel --sshlogin node01.lan --trc /tmp/{/.}.wav oggdec {} -o /tmp/{/.}.wav ::: *.ogg

    Dodám, že {./} je nahrazeno za název ...
    Takže {./} nebo {/.}?
    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
    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
    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
    Jde nejak udelat ta funkce bez bashe, treba v dash? Tedy mam skript o vice radcich, co chci spustit na kazdy soubor
    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
    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
    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
    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   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.