Ich versuche, Kundendaten in großen Mengen zu bearbeiten (ein paar tausend Datensätze), und Magento verfügt immer noch nicht über genügend verfügbaren Speicher, um das Skript auszuführen.
Nach einigen Tests mit memory_get_usage()
dem Täter scheint dies die $customer->save()
Methode zu sein, die 5 MB Speicher für jede Speicherung benötigt, diese aber nicht freigibt, wenn sie abgeschlossen ist.
Wenn Sie ein paar tausend Datensätze durchlaufen, wird daher nicht genügend Speicher ausgeführt.
Folgendes habe ich bisher versucht:
$customer->clearInstance()
unset($customer)
Dies scheint jedoch nicht zu helfen.
Unten ist mein Code:
public function createCustomerAddress($customerAddressData, $email){
$customer = Mage::getModel('customer/customer');
$customer->setWebsiteId(Mage::app()->getWebsite()->getId());
$customer->loadByEmail($email);
$address = Mage::getModel('customer/address');
$address->addData($customerAddressData);
$customer->addAddress($address);
unset($address);
try{
$customer->save();
}catch (Exception $e){
var_dump($customerAddressData);
var_dump($e->getMessage());
}
echo "\n" . "Before unsetting \n" . memory_get_usage() . "\n";
$customer->clearInstance();
unset($customer);
echo "\n" . "After \n" . memory_get_usage() . "\n"; // no difference than before
}
Jede Hilfe wäre sehr dankbar.
ps Ich bin mir nicht sicher, ob die clearInstance()
Funktion (im Mage_Core_Model_Abstract) irgendetwas tut. Wenn jemand einen Einblick in diese Funktion hat, wäre es sehr dankbar, wenn sie geteilt würde :)
quelle
Antworten:
Ich denke, dass dies mit einem Kernproblem von PHP zusammenhängt, das ohne umfangreiche Änderungen an den Magento-Kerndateien nicht einfach zu lösen ist.
Die einzige Möglichkeit, dies zu erreichen, ist die Verwendung einer Problemumgehung:
Ich schlage vor:
ein. Wenn dies vom Browser aus aufgerufen wird, würde ich einen separaten Ajax-Aufruf durchführen, wie @Julien Lacal in seiner Antwort empfohlen hat.
b. Wenn dies alles serverseitig erledigt wird, würde ich dies in zwei Skripte
createCustomerAddress
aufteilen , wobei 1. eines die vorhandene Kundenliste durchläuft und 2. eines die Funktion mithilfe von Post-Parametern aufruft. Das zweite Skript sollte dann mit CURL aus dem ersten Skript aufgerufen werden, damit jede Instanz des zweiten Skripts isoliert ausgeführt wird und nicht vom Speicherverlust betroffen ist.quelle
Der Speicher wird erst freigegeben, wenn keine Verweise auf diese Variable / dieses Objekt vorhanden sind. Ich vermute - und werde meine Antwort nach Bestätigung bearbeiten, dass das Ereignissystem in Magento eine Instanz des Modells an den Beobachter weitergibt und daher im Speicher ein Verweis darauf vorhanden ist.
Dies ist jedoch ein gut dokumentiertes Problem. (eine, die ich 2011 kommentiert habe http://www.magentocommerce.com/boards/viewthread/26561/ ).
quelle
Ich glaube, dies ist ein bekanntes Problem auf allen Plattformen und Versionen von Magento.
unset()
oderclearInstance()
wird keine Wirkung haben.Mage::getModel()
Speicherverlust in allen Fällen, auf die ich gestoßen bin (Kunden, Produkte, Bestellungen usw.). Der einzige Weg, den ich gefunden habe, besteht darin, wenn möglich eine Sammlung zu verwenden (möglicherweise nicht für Sie zutreffend), wenn Sie mit einer großen Anzahl von Objekterstellungen arbeiten. Wenn Ihr Vorgang abgeschlossen ist, wird der Speicher freigegeben.Haben Sie nicht mehr genügend Speicher? Dies ist normalerweise kein Problem, es sei denn, Sie sind es. Wenn Ihnen möglicherweise der Arbeitsspeicher ausgeht, können Sie versuchen, den Massenprozess in separate Läufe in Ihrer Erweiterung aufzuteilen. Wenn dies in einem Shell-Skript enthalten ist, ist es einfach, es aufzubrechen. Erstellen Sie einfach zwei oder mehr Dateien und führen Sie sie nacheinander mit vordefinierten Kundenbereichen aus
entity_id
.quelle
Eine gute Problemumgehung wäre, ein eigenes Administrationsmodul für den Massenkundenimport zu erstellen und Ajax-Aufrufe an einen Controller zu verwenden, um Daten in kleineren Gruppen zu importieren. Auf diese Weise wird Ihnen nicht der Arbeitsspeicher ausgehen, da bei jedem Ajax-Aufruf ein neuer Prozess gestartet wird, anstatt aufgrund des
Mage::getModel('customer/address')
quelle
Scheint, als hätte ich beim Anrufen einen großen Speicherverlust festgestellt
Model::save()
Nachdem das Element in der Datenbank gespeichert wurde, gibt es den folgenden Code in der genannten Methode:
Auf diese Weise wird das Modell dem statischen Parameter hinzugefügt
$_commitCallbacks
. Die Methode wird entfernt, wenn die Transaktionsebene nur auf Null gesetzt ist.Um dies zu lösen, fügen Sie Ihrem eigenen Ressourcenmodell entweder den folgenden Code hinzu:
Dies funktioniert nur für einen Ressourcentyp. Sie müssen dies für alle Ressourcenmodelle tun, die in Ihrer Schleife häufig aktualisiert werden. Ein Nachteil ist, dass die Methode
afterCommitCallback()
Ihres Modells niemals aufgerufen wird.Eine andere (bessere) Möglichkeit besteht darin, die Methoden und zu überschreiben
commit()
undrollback()
das Modell in jedem Fall aus der Variablen zu entfernen.quelle