सिद्धांत के साथ बैच प्रसंस्करण iterate()
और IterableResult
की सहायता से, यह लगता है की तुलना में अधिक कठिन है।
जैसा कि आपको उम्मीद है कि IterableResult
का सबसे बड़ा लाभ यह है कि यह सभी तत्वों को स्मृति में लोड नहीं करता है, और दूसरा लाभ यह है कि यह आपके द्वारा लोड की गई इकाइयों के संदर्भ नहीं रखता है, इस प्रकार IterableResult
जीसी को रोकता नहीं है अपनी इकाई से स्मृति मुक्त करने से।
हालांकि वहाँ किसी अन्य वस्तु सिद्धांत के EntityManager
(खासतौर पर UnitOfWork
) जो प्रत्येक वस्तु जो आप स्पष्ट या परोक्ष (EAGER
संघों) पूछे सभी संदर्भों को आयोजित करता है।
सरल शब्दों में, जब भी आप भी DQL
प्रश्नों और भी IterableResult
के माध्यम से findAll()
findOneBy()
द्वारा लौटाए गए किसी भी संस्था (एँ) मिलता है, तो उन संस्थाओं में से प्रत्येक के लिए एक संदर्भ सिद्धांत के अंदर सहेजा गया है। संदर्भ बस एक Assoc सरणी में संग्रहीत किया जाता है, यहाँ स्यूडोकोड है: $identityMap['Acme\Entities\Image'][0] = $image0;
तो क्योंकि आपके पाश से प्रत्येक यात्रा पर, अपने पिछले छवियों (पाश की गुंजाइश या IterableResult
के दायरे में मौजूद नहीं होने के बावजूद) अभी भी अंदर मौजूद हैं इस identityMap
में, जीसी उन्हें साफ़ नहीं कर सकता है और आपकी स्मृति खपत वही है जब आप findAll()
पर कॉल कर रहे थे।
अब कोड के माध्यम से जाना और देखते हैं कि वास्तव में क्या हो रहा है
$query = $this->em->createQuery('SELECT i FROM Acme\Entities\Image i');
// यहाँ सिद्धांत केवल क्वेरी वस्तु, यहाँ
$iterable = $query->iterate();
// कोई डाटाबेस पहुँच findAll विपरीत बनाता जाने(), इस कॉल पर कोई डीबी एक्सेस नहीं होती है। // यहाँ क्वेरी उद्देश्य केवल एक इटरेटर
while (($image_row = $iterable->next()) !== false) {
// now upon the first call to next() the DB WILL BE ACCESSED FOR THE FIRST TIME
// the first resulting row will be returned
// row will be hydrated into Image object
// ----> REFERENCE OF OBJECT WILL BE SAVED INSIDE $identityMap <----
// the row will be returned to you via next()
// to access actual Image object, you need to take [0]th element of the array
$image = $image_row[0];
// Do something here!
write_image_data_to_file($image,'myimage.data.bin');
//now as the loop ends, the variables $image (and $image_row) will go out of scope
// and from what we see should be ready for GC
// however because reference to this specific image object is still held
// by the EntityManager (inside of $identityMap), GC will NOT clean it
}
// and by the end of your loop you will consume as much memory
// as you would have by using `findAll()`.
में लपेटा जाता है तो सबसे पहले समाधान वास्तव में सिद्धांत EntityManager बताने के लिए $identityMap
से वस्तु को अलग करने के लिए है। मैंने इसे और अधिक पठनीय बनाने के लिए while
लूप को foreach
पर भी बदल दिया।
foreach($iterable as $image_row){
$image = $image_row[0];
// do something with the image
write_image_data_to_file($image);
$entity_manager->detach($image);
// this line will tell doctrine to remove the _reference_to_the_object_
// from identity map. And thus object will be ready for GC
}
हालांकि उपरोक्त उदाहरण कुछ खामियां है, भले ही यह doctrine's documentation on batch processing में चित्रित किया है। यह अच्छी तरह से काम करता है, अगर आपकी इकाई Image
EAGER
किसी भी संगठन के लिए लोड नहीं कर रही है। लेकिन अगर आप किसी भी संगठन को ईमानदारी से लोड कर रहे हैं उदाहरण के लिए। :
/*
@ORM\Entity
*/
class Image {
/*
@ORM\Column(type="integer")
@ORM\Id
*/
private $id;
/*
@ORM\Column(type="string")
*/
private $imageName;
/*
@ORM\ManyToOne(targetEntity="Acme\Entity\User", fetch="EAGER")
This association will be automatically (EAGERly) loaded by doctrine
every time you query from db Image entity. Whether by findXXX(),DQL or iterate()
*/
private $owner;
// getters/setters left out for clarity
}
तो अगर हम के रूप में ऊपर कोड के एक ही हिस्से का उपयोग करें, पर
foreach($iterable as $image_row){
$image = $image_row[0];
// here becuase of EAGER loading, we already have in memory owner entity
// which can be accessed via $image->getOwner()
// do something with the image
write_image_data_to_file($image);
$entity_manager->detach($image);
// here we detach Image entity, but `$owner` `User` entity is still
// referenced in the doctrine's `$identityMap`. Thus we are leaking memory still.
}
संभव समाधान EntityManager::clear()
का उपयोग करने के बजाय या EntityManager::detach()
जो पूरी तरह से साफ हो जाएगा पहचान मानचित्र हो सकता है।
foreach($iterable as $image_row){
$image = $image_row[0];
// here becuase of EAGER loading, we already have in memory owner entity
// which can be accessed via $image->getOwner()
// do something with the image
write_image_data_to_file($image);
$entity_manager->clear();
// now ``$identityMap` will be cleared of ALL entities it has
// the `Image` the `User` loaded in this loop iteration and as as
// SIDE EFFECT all OTHER Entities which may have been loaded by you
// earlier. Thus you when you start this loop you must NOT rely
// on any entities you have `persist()`ed or `remove()`ed
// all changes since the last `flush()` will be lost.
}
तो उम्मीद है कि यह सिद्धांत पुनरावृत्ति को थोड़ा सा समझने में मदद करता है।
यह उत्तर बिल्कुल मदद नहीं करता है। – naitsirch