Nette Utils: generátory výkonu a efektivity

před měsícem od David Grudl  

Nette Framework přináší výkonnostní výhody a optimalizaci práce s pamětí využitím tzv. generátorů. Tyto novinky vám umožní pracovat s velkými datovými sadami elegantněji a efektivněji, aniž byste museli měnit způsob, jakým píšete svůj kód. Pojďme se podívat na tři oblasti, kde Nette využívá sílu generátorů způsobem, který možná překvapí i zkušené vývojáře.

Čtení souborů po řádcích s FileSystem::readLines()

Práce s velkými soubory byla vždy výzvou, zejména pokud jde o paměťovou náročnost. Nette přichází s elegantním řešením v podobě metody FileSystem::readLines().

use Nette\Utils\FileSystem;

$lines = FileSystem::readLines('large_file.txt');
foreach ($lines as $number => $line) {
    echo "Řádek $number: $line\n";
    // Zpracování řádku...
}

Na první pohled se může zdát, že tento kód dělá totéž co nativní funkce PHP file(). Ale zdání klame. Zatímco file() načte celý soubor do paměti najednou, což může být problematické u velkých souborů, readLines() využívá generátor k postupnému čtení souboru.

Klíčové výhody:

  • Nízká paměťová náročnost: Soubor se čte průběžně, v paměti je vždy jen jeden řádek.
  • Okamžité zpracování: Nemusíte čekat na načtení celého souboru.
  • Práce s libovolně velkými soubory: Velikost souboru není omezena dostupnou pamětí.
  • Přirozené rozhraní: Z pohledu programátora se kód píše stejně snadno.

Toto řešení je ideální pro zpracování logů, velkých datových exportů nebo jakýchkoliv rozsáhlých textových souborů.

Lazy regulární výrazy se Strings::matchAll()

Metoda Strings::matchAll() dostala v nové verzi Nette Utils 4.0.5 zajímavý upgrade. Nový parametr $lazy umožňuje postupné zpracování řetězce při hledání shod s regulárním výrazem.

use Nette\Utils\Strings;

$text = file_get_contents('very_long_text.txt');
$pattern = '/\b\w{5,}\b/'; // slova s 5 a více znaky

$matches = Strings::matchAll($text, $pattern, lazy: true);
foreach ($matches as $match) {
    echo "Nalezeno slovo: {$match[0]}\n";
    // Můžeme kdykoliv přerušit zpracování
    if ($match[0] === 'konec') {
        break;
    }
}

Bez parametru lazy by se rovnou prohledal celý text a všechny shody by se uložily do paměti. S lazy: true se text prochází postupně a shody se hledají za běhu.

Výhody:

  • Rozložení výkonu: Zpracování probíhá průběžně, ne v jednom velkém bloku.
  • Možnost předčasného ukončení: Můžete přestat hledat, jakmile najdete, co potřebujete.
  • Přirozené rozhraní: Z pohledu programátora se kód píše stále stejně

Toto je zvláště užitečné při analýze velkých textů, parsování logů nebo při hledání specifických vzorů v rozsáhlých datech.

Efektivní práce pomocí třídy Iterables

Nová třída Iterables přináší sadu metod pro práci s iterovatelnými strukturami, jde o obdobu toho, co nabízí Arrays pro pole. Navíc však má metody, které jsou optimalizovány pro postupné zpracování. Pojďme si ukázat, jak je můžete využít ve vašem kódu.

use Nette\Utils\Iterables;

$numbers = // velké množství dat

// filtrování prvků
$evenNumbers = Iterables::filter($numbers, fn($n) => $n % 2 === 0);

// transformace prvků
$squared = Iterables::map($numbers, fn($n) => $n * $n);

// transformace klíčů i hodnot
$squaredKeys = Iterables::mapWithKeys($fruits, fn($v, $k) => [$k * $k, $n]);

Klíčovou výhodou je líné vyhodnocování, kdy transformace se provádí až v momentě, kdy je prvek skutečně potřeba. Můžete kdykoliv ukončit iteraci a ušetřit tak výpočetní čas:

foreach ($evenNumbers as $number) {
    if ($number > 20) break; // Můžeme kdykoliv ukončit
}

Tyto metody jsou zvláště užitečné při práci s velkými kolekcemi dat, jako jsou rozsáhlé databázové výsledky nebo při zpracování streamů dat. Navíc jsou zcela transparentní a můžete je začít používat okamžitě, aniž byste museli zásadně měnit strukturu vašeho kódu. Nette se snaží přinášet pokročilé funkce způsobem, který je přístupný a snadno použitelný pro vývojáře všech úrovní.

Komentáře (RSS)

  1. Tleskám, samé super věci 🙂

    Těším se, až se dostaneš na fibers

    před měsícem
  2. Super nápad. FileSystem::readLines i Strings::matchAll se budou určitě hodit.

    před měsícem
  3. Super, díky Davide

    před 22 dny
  4. +1

    před 4 dny

Chcete-li odeslat komentář, přihlaste se