2011-01-12 25 views
7

यह एक साधारण प्रोग्रामिंग प्रश्न है, जो कि foreach लूप के दौरान PHP की सरणी प्रतिलिपि बनाने और परेशान करने के बारे में ज्ञान की कमी से आ रहा है। ऐसा इस तरह है, मेरे पास एक सरणी है जो मेरे द्वारा एक बाहरी स्रोत से स्वरूपित है जिस तरह से मैं बदलना चाहता हूं। एक साधारण उदाहरण होगा:स्मृति पर सहेजने के दौरान सरणी मानों को अनसेट करना क्या करता है?

$myData = array('Key1' => array('value1', 'value2')); 

लेकिन क्या मैं की तरह कुछ हो जाएगा चाहते हैं:

$myData = array([0] => array('MyKey' => array('Key1' => array('value1', 'value2')))); 

तो मैं पहले $myData लेने के लिए और दूसरा $myData तरह स्वरूपित। मैं अपने स्वरूपण एल्गोरिदम के साथ पूरी तरह से ठीक हूँ। मेरा सवाल स्मृति को बचाने के लिए एक रास्ता खोजने में निहित है क्योंकि इन सरणीओं को थोड़ा कमजोर हो सकता है। तो, मेरे foreach लूप के दौरान मैं वर्तमान सरणी मान को नए प्रारूप में कॉपी करता हूं, फिर मैं उस मूल मान को अनसेट करता हूं जिसे मैं मूल सरणी से काम कर रहा हूं। उदा .:

$formattedData = array(); 
foreach ($myData as $key => $val) { 
    // do some formatting here, copy to $reformattedVal 

    $formattedData[] = $reformattedVal; 

    unset($myData[$key]); 
} 

unset() यहाँ एक अच्छा विचार करने के लिए कॉल है? यानी, क्या यह स्मृति को संरक्षित करता है क्योंकि मैंने डेटा कॉपी किया है और अब मूल मूल्य की आवश्यकता नहीं है? या, PHP स्वचालित रूप से डेटा एकत्रित करता है क्योंकि मैं किसी भी बाद के कोड में इसका संदर्भ नहीं देता हूं?

कोड ठीक चलाता है, और अब तक मेरे डेटासेट प्रदर्शन अंतरों के परीक्षण के लिए आकार में बहुत नगण्य रहे हैं। मुझे नहीं पता कि मैं बाद में कुछ अजीब बग या सीपीयू हिट के लिए खुद को स्थापित कर रहा हूं या नहीं।

किसी भी अंतर्दृष्टि के लिए धन्यवाद।
-sR

+0

जब तक अपने डेटा strucutes absolutly विशाल कर रहे हैं (अपने राम के एक बड़े अंश) तो आप कुछ भी नहीं के बारे में चिंता कर रहे हैं। यदि php एक मेनोरी चलाता है तो यह आपको बताएगा, और आप इसे php.ini में बढ़ा सकते हैं। – Ian

+4

यह एक * मूर्ख विचार * है। आपने अभी एक साइड-इफेक्ट पेश किया है जिसे बाद में कुछ * माइक्रो-ऑप्टिमाइज़ेशन * के लिए भुला दिया जा सकता है: -/और नहीं, PHP (न ही कोई अन्य मानक जीसी भाषा जिसे मैं जानता हूं) डेटा * निहित * बनाने में सक्षम है डेटा कंस्ट्रक्शन पुनर्निर्माण के लिए उपलब्ध है जबकि * कंटेनर * के संदर्भ में मौजूद है (इसमें नरम/कमजोर संदर्भों जैसे विचार शामिल नहीं हैं)। 'अनसेट' PHP जीसी को लात मारने का कारण बन सकता है, लेकिन वास्तविक प्रदर्शन प्राप्त हुआ - यदि कोई हो - जारी किए गए स्मृति दबाव के कारण सामान्यीकृत करने के लिए तुच्छ नहीं है। यदि यह * एक समस्या बन जाती है, * तो * इसे संबोधित करें। –

+0

इस सरणी का आकार क्या है? –

उत्तर

0

जब तक आप संदर्भ unsetting द्वारा तत्व पहुँच बना रहे हैं जो भी कोई कार्य नहीं करेगा, जैसा कि आप इटरेटर भीतर दौरान सरणी बदल नहीं सकते।

यह कहा जाता है कि इसे आम तौर पर आपके द्वारा पुन: एकत्रित किए गए संग्रह को संशोधित करने के लिए बुरी आदत माना जाता है - एक बेहतर तरीका स्रोत सरणी को छोटे हिस्सों में तोड़ना होगा (केवल एक समय में स्रोत डेटा का एक हिस्सा लोड करके) और इन प्रक्रियाओं को संसाधित करते समय, प्रत्येक संपूर्ण सरणी "खंड" को अनसेट करते हुए।

+0

"unsetting जो भी कोई कार्य नहीं करेगा" - यह सही नहीं है, अपने कोड मूल सरणी – Andy

+0

से चर अनसेट जाएगा @Andy मैं स्पष्ट रूप से यह कुछ नहीं करेंगे, अगर यह है ** संदर्भ द्वारा पहुँचा नहीं कहा गया है **। PHP मैनुअल से - "जब तक सरणी का संदर्भ नहीं दिया जाता है, तो foreach निर्दिष्ट सरणी की एक प्रति पर चलता है, न कि सरणी स्वयं।" –

+0

सही है, लेकिन आप देखेंगे कि उसका कोड मूल सरणी से वैरिएबल को अनसेट कर रहा है, प्रतिलिपि नहीं। – Andy

4

& ऑपरेटर का उपयोग कर foreach लूप में चर के संदर्भ का उपयोग करें। यह foreach के लिए मेमोरी में सरणी की प्रतिलिपि बनाने से बचाता है।

संपादित करें: के रूप में चर unsetting Artefacto द्वारा बताया केवल मूल चर के सन्दर्भ की संख्या कम हो जाती है, तो स्मृति को बचाया बल्कि चर के मूल्य की तुलना में संकेत पर ही है। विचित्र रूप से संदर्भ का उपयोग करके कुल मेमोरी उपयोग बढ़ जाता है क्योंकि अनुमानित रूप से संदर्भ को संदर्भित करने के बजाय मान को नए स्मृति स्थान पर कॉपी किया जाता है।

जब तक सरणी संदर्भित है, foreach निर्दिष्ट सरणी की एक प्रति और न सरणी पर ही चल रही है। एरे पॉइंटर पर foreach कुछ दुष्प्रभाव है। पर रीसेट किए बिना फ़ोरैच के दौरान या उसके बाद सरणी सूचक पर भरोसा न करें।

उपयोग memory_get_usage() आप कितनी स्मृति का उपयोग कर रहे पहचान करने के लिए।

वहाँ स्मृति के उपयोग और आवंटन here पर एक अच्छा लिखने निर्भर है। टिप्पणी की लाइनों uncommenting विभिन्न परिदृश्यों में कुल स्मृति उपयोग देखने की कोशिश -

यह देखने के लिए स्मृति आवंटन उपयोगी परीक्षण कोड है।

echo memory_get_usage() . PHP_EOL; 
$test = $testCopy = array(); 
$i = 0; 
while ($i++ < 100000) { 
    $test[] = $i; 
} 
echo memory_get_usage() . PHP_EOL; 
foreach ($test as $k => $v) { 
//foreach ($test as $k => &$v) { 
    $testCopy[$k] = $v; 
    //unset($test[$k]); 
} 
echo memory_get_usage() . PHP_EOL; 
+0

उत्तर और उपयोगी जानकारी के लिए धन्यवाद। आपके कोड उदाहरण का उपयोग करके, मैं 'unset()' का उपयोग करते समय स्मृति उपयोग में 5 एमबी diff के बारे में देख रहा हूं। इसके अलावा, स्मृति उपयोग * ऊपर जाता है * फोरच में सरणी का संदर्भ देते समय ('अनसेट() 'का उपयोग नहीं करते समय) दिलचस्प ... हालांकि उस पर पर्याप्त समय बिताया गया। – Soulriser

+0

वास्तव में सही नहीं है, नीचे Artefacto का जवाब देखें! – GTodorov

2

"स्वरूपण" में किसी भी बिंदु पर यदि आप कुछ पसंद है:

$reformattedVal['a']['b'] = $myData[$key]; 

फिर unset($myData[$key]); कर अप्रासंगिक स्मृति के लिहाज से है क्योंकि आप केवल चर के संदर्भ गिनती है, जो अब घट रही है दो स्थानों में मौजूद है ($myData[$key] और $reformattedVal['a']['b'] के अंदर)। असल में, आप मूल सरणी के अंदर चर को अनुक्रमणित करने की स्मृति को सहेजते हैं, लेकिन यह लगभग कुछ भी नहीं है।

+0

यह सही नहीं है - डिफ़ॉल्ट चर से संदर्भ द्वारा पारित नहीं किया गया है, केवल वस्तुओं – Andy

+1

@ एंडी पहले कोई भी कुछ गुजर रहा है (क्या आप कोई फ़ंक्शन देखते हैं?), दूसरा, सामान्य परिस्थितियों में '$ a = $ b' के असाइनमेंट में कोई स्मृति नहीं दो चर के बीच प्रतिलिपि बनाई गई है (PHP प्रतिलिपि प्रतिलिपि लागू करता है), भले ही यह व्यवहार करता है जैसे कि स्मृति की प्रतिलिपि बनाई गई थी। – Artefacto

+0

मेरी गलती, मैं मानकों को पारित करने के बजाय असाइनमेंट का इरादा रखता हूं। मैंने 'unset() 'का उपयोग करके सहेजी गई स्मृति को प्रदर्शित करने के लिए मेरे उत्तर में टेस्ट कोड जोड़ा है। – Andy

3

याद rules of Optimization Club करें:

  1. अनुकूलन क्लब का पहला नियम है, तो आप का अनुकूलन नहीं है।
  2. ऑप्टिमाइज़ेशन क्लब का दूसरा नियम है, आप मापने के बिना अनुकूलित नहीं करते हैं।
  3. यदि आपका ऐप अंतर्निहित परिवहन प्रोटोकॉल से तेज़ी से चल रहा है, तो ऑप्टिमाइज़ेशन खत्म हो गया है।
  4. एक समय में एक कारक।
  5. कोई मार्केटरोइड नहीं, कोई मार्केट्रॉइड शेड्यूल नहीं।
  6. परीक्षण तब तक जारी रहेगा जब तक इसे करना होगा।
  7. यदि यह ऑप्टिमाइज़ेशन क्लब में आपकी पहली रात है, तो आपको एक टेस्ट केस लिखना होगा।

नियम # 1 और # 2 यहाँ विशेष रूप से प्रासंगिक हैं। जब तक आप नहीं जानते कि आपको अनुकूलित करने की आवश्यकता है, और जब तक कि आपने इसे अनुकूलित करने की आवश्यकता को माप नहीं लिया है, तो इसे न करें। अनसेट जोड़ने से रन-टाइम हिट मिल जाएगी और भविष्य में प्रोग्रामर बनेंगे क्यों आप इसे कर रहे हैं।

इसे अकेला छोड़ दें।

+0

# 5 का मतलब क्या है – Jason

+0

"मार्केट्रॉइड" का मतलब विपणन विभाग से है। बड़े अर्थ में, किसी को गैर-तकनीकी निर्देशों को आपके बारे में बताएं कि आपके प्रोग्राम को क्या करने में सक्षम होना चाहिए। –

+0

संदर्भ के लिए धन्यवाद, एंडी। मैं मार्केटरोड्स को बहुत अच्छी तरह से जानता हूं। – Soulriser

2

मैं स्मृति से बाहर चल रहा था एक पाश के भीतर एक पाठ (xml) फ़ाइल की तर्ज संसाधित करते समय। इसी तरह की स्थिति के साथ किसी के लिए, यह मेरे लिए काम किया:

while($data = array_pop($xml_data)){ 
    //process $data 
}