Portál AbcLinuxu, 10. června 2024 15:26


Dotaz: Čtení ze vstupu v Perlu

7.3.2017 20:46 RM
Čtení ze vstupu v Perlu
Přečteno: 340×
Odpovědět | Admin
Najde se někdo Perlu znalý do té míry, že by mi dokázal vysvětlit, proč perl s přepínačem -p (tj. aktivní print interně) je pomalejší než s použitím přepínače -n a příkazem print.
time perl -ne 'print $_' longlist.txt    #  0.36s
time perl -pe ' ' longlist.txt    #  0.47s
A také proč? :
open FH, "<", "longlist.txt";
print <FH>    # 0.5s
print while (<FH>)   # 0.32s
Logicky bych očekával v obou případech opak.
Nástroje: Začni sledovat (2) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

wamba avatar 8.3.2017 00:12 wamba | skóre: 38 | blog: wamba
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Odpovědět | | Sbalit | Link | Blokovat | Admin
v prvním případě nemůžu potvrdit u mě je to víceméně nastejno. Nicméně
perl -pe ' ' longlist.txt
lze zapsat pomocí -n přibližně takto
perl -ne '} continue { print'
V druhém případě, první varianta načte pole řádků a pak je vytiskne. Pravděpodobně očekáváš slurp, to lze následovně
{local $/; print <> }
nebo přepínačem -0777 (i při one-lineru).

Záleží, co to ve výsledku má dělat. Někdy je užitečný File::Slurp.
This would have been so hard to fix when you don't know that there is in fact an easy fix.
8.3.2017 10:00 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Zkoušel jsem to na souboru, který měl 250k krátkých řádků, výstup byl přesměrovaný do /dev/null.

Nee, slurp neočekávám. Jen mi vrtá hlavou, proč čtení a zápis v jednom kuse <FH> trvá déle než čtení a zápis každého řádku zvlášť. Logicky bych čekal, že ze vstupního bufferu bude perl rychlejší, pokud vše jen vyvrhne (v tomto případě několikrát), než když musí procházet buffer a každý řádek přečíst pomocí readline(), tj. na ukončovacím znak řádku.
8.3.2017 15:35 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
K zamyšlení mne vedlo:
print +(<FH>)[1..200_000];
$. < 200_2002 && print while (<FH>);
V tomto případě je výsledný čas téměř stejný, což je logické, protože se stejně musí v obou případech číst pomocí readline() a testovat.
8.3.2017 15:49 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
... možná právě to je důvod ;). Totiž že print (<FH>) tam má tuhle podmínku i pro plný rozsah a chová se tak stejně jako zápis s && vždy a žádná kouzla s rychlejším vyvrhnutím se nekonají, jak jsem si myslel. Čas by tomu i odpovídal.
8.3.2017 07:56 Milan Straka
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Odpovědět | | Sbalit | Link | Blokovat | Admin
Podle dokumentace obalí -p skript do následujícího cyklu:
while (<>) {
    ...             # your program goes here
} continue {
    print or die "-p destination: $!\n";
}
Když měřím -pe '' a -ne '} continue { print or die ""}' tak už mi to vychází stejně.
8.3.2017 10:53 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Skutečně je to tak a zdá se, že příčinou zpomalení je ten operátor or. Já jsem tomu modelu v manuálu moc nevěřil, ale tohle tedy sedí.

(Ve skutečnosti je to uvnitř zadrátované asi trochu jinak, a ten buffer, který si představujeme pod <> se nějak obchází. Minimálně při nastavování vstupní vrstvy :utf8, kdy se nastaví flag jen u proměnné $_ a <> zůstane netknuté.)

8.3.2017 11:20 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Ještě k tomu nastavení flagu. Ono i to bude zřejmě odpovídat. Jenomže prostě open use open IO => ":encoding(utf8)", ":std" se v tomto případě nedá umístit před while a nastavení má platnost až od místa zavolání (není to pragma).
8.3.2017 16:52 RM
Rozbalit Rozbalit vše Re: Čtení ze vstupu v Perlu
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ještě jsem provedl experiment s tím flagem: dal jsem uvedené use open ... do sekce BEGIN{}. Výsledek je stejný -- nastavení se dotkne jen proměnné $_. Já se tedy domnívám že one-linery s přepínači -ne a -pe vstupní buffer nepoužívají (nebo nějak skrytě) a čte se řádek po řádku do proměnné $_ (stejně jak to má awk). A protože není na výstupu už potřeba testovat pozici a pracovat s ukazatele, je one-liner rychlejší.

U několika velkých souborů zpracovávaných současně se tedy vyplatí naforkovat několik one-linerů než část běžného kódu pracujícícho s <FH>. Samozřejmě pokud není potřeba předávat data rodiči, ale i to se případně dá provést přes roury; vyzkoušeno, je to pak rychlejší než běžné forky v rámci programu.

Díky za rady. Myslím, že se mi to povedlo rozmotat.

Založit nové vláknoNahoru

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

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