Šiukšlių rinkimas PHP aplinkoje

Tikriausia kiekvienas PHP programuotojas, kuris yra susidūręs su ilgai vykdomais sunkiais procesais, pastebėjo, kad PHP programa nuolat lėtėja. Itin gerai tai žino Magento integravę žmonės, kai reikia importuoti didelį kiekį prekių iš išorinių šaltinių. Tai įvyksta todėl, kad neefektyviai naudojama operatyvioji atmintinė, kurioje kaupiasi šiukšlės ir trikdo programos darbą su atmintimi, blogiausiu atveju programa nutraukia darbą, nes viršyja numatytą didžiausią atminties kiekį.
Kai kurie tikriausia pagalvojo – Magento… Teisingai! Tikrai opi problema, kuriai atrodo, kad nėra sprendimo. Taigi apie tai ir pakalbėkime.

Tipinis prekių importavimo į Magento sistemą kodas:

Mage::app();
date_default_timezone_set('Europe/Vilnius');
Mage::app()->setCurrentStore(0);
$product = Mage::getModel('catalog/product');
/**
* veiksmai pagal jūsų situaciją
**/
$product->load($product_id);
$product->setStockData($stockData);
$product->setCategoryIds($ids);
$product->save();

Sistemėlė paprasta, tačiau mano atveju ~20 000 prekių importuojasi apie 1.5 valandos (serveris: 60% CPU, 1GB RAM). Esant daug didesniems kiekiams reikia ir didesnių resursų ir daugiau laiko.
Internete radau vieną būdą pagreitinti importavimą, reikia paredaguoti /lib/Varien/Db/Select.php failą taip:
Originalas:

public function __construct(Zend_Db_Adapter_Abstract $adapter)
    {
        parent::__construct($adapter);
        self::$_joinTypes[] = self::STRAIGHT_JOIN_ON;
        self::$_partsInit = array(self::STRAIGHT_JOIN => false) + self::$_partsInit;
    }

Modifikuotas:

public function __construct(Zend_Db_Adapter_Abstract $adapter)
    {
        parent::__construct($adapter);
        if (!in_array(self::STRAIGHT_JOIN_ON, self::$_joinTypes))
        self::$_joinTypes[] = self::STRAIGHT_JOIN_ON;
        self::$_partsInit = array(self::STRAIGHT_JOIN => false) + self::$_partsInit;
    }

Pagreitėjo, tačiau siektino efekto nedavė, sistemai dirbant atminties sunaudojimas ir toliau augo…
Tačiau su PHP 5.3 atsirado galimybė „forsuoti“ šiukšlių surinkimą. http://www.php.net/manual/en/features.gc.collecting-cycles.php
Taigi papildome savo prekių importavimo sistemėlę:

Mage::app();
date_default_timezone_set('Europe/Vilnius');
Mage::app()->setCurrentStore(0);
$product = Mage::getModel('catalog/product');
/**
* veiksmai pagal jūsų situaciją
**/
$product->load($product_id);
$product->setStockData($stockData);
$product->setCategoryIds($ids);
$product->save();
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
    gc_collect_cycles();
}

Rezultatas tiesiog puikus! Importavimas užtruko ~10 minučių, atminties sunaudojimas neperkopė 4M ribos. Tačiau nereikia pamiršti, kad savo kode taip pat turite palaikyti tvarką: sunaikinti kintamuosius ar masyvus kurie yra nebereikalingi, neapsikrauti nereikalingais duomenimis.
Bandymo rezultatai grafikuose, kur 1. – Prekių importavimas, 2. – Modifikuotas importavimas:

CPU usage - by day


MySQL queries - by day

Žygimantas

Lead developer at Soundest. Zend Certified Engineer.

More Posts - Website

Žymos: , , ,

12 komentarų

Komentuoti: Web master Atšaukti atsakymą

El. pašto adresas nebus skelbiamas.