2017-04-24 11 views
5

में जे एस में वस्तु संपत्तियों के हटा दें। यह केवल आदिम कुंजी के लिए काम करता है, इसलिए कोई बाल्टी नहीं, कोई हैश-कोड इत्यादि। मुझे जिस समस्या का सामना करना पड़ा वह हटाई गई विधि को कार्यान्वित कर रहा है। सादा delete का उपयोग करना अस्वीकार्य रूप से धीमा है। बड़े मानचित्रों के लिए यह ES6 मानचित्र हटाने से 300-400x धीमी है। यदि वस्तु का आकार बड़ा है तो मैंने बड़े प्रदर्शन में गिरावट देखी है। नोड जे एस 7.9.0 (और उदाहरण के लिए क्रोम 57) पर अगर वस्तु 50,855 गुण है delete प्रदर्शन के रूप में ES6 मानचित्र में ही है। लेकिन 50856 गुणों के लिए ईएस 6 मानचित्र परिमाण के 2 आदेशों पर तेज़ है। यहाँ सरल कोड पुन: पेश करने के लिए है:धीरे बस अपने आप को मैं एक <a href="https://github.com/iskolbin/tsstringmap" rel="nofollow noreferrer">simple ES6 Map+Set-like implementation based on plain JS Object</a> लिखा टाइपप्रति का एक सा प्रशिक्षित करने के लिए वी 8

// for node 6: 76300 
 
// for node 7: 50855 
 
const N0 = 50855; 
 

 
function fast() { 
 
\t const N = N0 
 

 
\t const o = {} 
 
\t for (let i = 0; i < N; i++) { 
 
\t \t o[i] = i 
 
\t } 
 

 
\t const t1 = Date.now() 
 
\t for (let i = 0; i < N; i++) { 
 
\t \t delete o[i] 
 
\t } 
 
\t const t2 = Date.now() 
 

 
\t console.log(N/(t2 - t1) + ' KOP/S') 
 
} 
 

 
function slow() { 
 
\t const N = N0 + 1 // adding just 1 
 

 
\t const o = {} 
 
\t for (let i = 0; i < N; i++) { 
 
\t \t o[i] = i 
 
\t } 
 

 
\t const t1 = Date.now() 
 
\t for (let i = 0; i < N; i++) { 
 
\t \t delete o[i] 
 
\t } 
 
\t const t2 = Date.now() 
 

 
\t console.log(N/(t2 - t1) + ' KOP/S') 
 
} 
 

 
fast() 
 

 
slow()

मुझे लगता है मैं delete गुण के बजाय सकता है सिर्फ undefined या कुछ गार्ड वस्तु के लिए उन्हें सेट है, लेकिन इस इच्छा गड़बड़ कोड, क्योंकि hasOwnProperty नहीं होगा सही ढंग से काम करें, for...in लूप को अतिरिक्त चेक की आवश्यकता होगी और इसी तरह। क्या कोई और अच्छा समाधान है?

पीएस मैं नोड 7.9.0 का उपयोग कर रहा पर OSX सिएरा

संपादित टिप्पणियाँ लोगों के लिए धन्यवाद, मैं ओ पी/एस => KOP/एस तय की। मुझे लगता है कि मैंने बल्कि बुरी तरह से निर्दिष्ट सवाल पूछा, इसलिए मैंने शीर्षक बदल दिया। कुछ जांच के बाद मुझे पता चला कि उदाहरण के लिए फ़ायरफ़ॉक्स में ऐसी कोई समस्या नहीं है - लागत को हटाना रैखिक रूप से बढ़ता है। तो यह सुपर स्मार्ट वी 8 की समस्या है। और मुझे लगता है कि यह सिर्फ एक बग :(

+0

मुझे ओएस एक्स पर क्रोम में एक ही प्रभाव दिखाई देता है। – Barmar

+0

संबंधित: http://stackoverflow.com/questions/27397034/why-is-delete-slow-in-javascript –

+0

हां, 'हटाएं' है धीमी होने के लिए जाना जाता है – Bergi

उत्तर

6

(। वी 8 डेवलपर यहाँ) नहीं है तुम बस गणना सेशन/गलत समय बीत चुका, मिलीसेकेंड में है ही सेकंड में नहीं तो आप 1000 से गुणा करने के लिए है हाँ, यह एक ज्ञात मुद्दा है। अंतर्निहित समस्या यह है कि वस्तुओं को अपने तत्वों को बैकिंग स्टोर को एक फ्लैट सरणी से एक शब्दकोश में स्विच करना चाहिए जब वे बहुत दुर्लभ हो जाते हैं, और जिस तरह से इसे ऐतिहासिक रूप से कार्यान्वित किया गया है प्रत्येक delete ऑपरेशन के लिए यह जांचने के लिए कि क्या संक्रमण अभी भी होने के लिए के लिए पर्याप्त तत्व मौजूद नहीं थे। सरणी जितनी बड़ी थी, इस चेक ने जितना अधिक समय लिया था। कुछ स्थितियों के तहत (हाल ही में एक निश्चित आकार के नीचे बनाई गई वस्तुओं), चेक छोड़ दिया गया था - जिसके परिणामस्वरूप प्रभावशाली गतिशीलता fast() मामले में आप देख रहे हैं।

मैंने नियमित/धीमी पथ के (स्पष्ट रूप से काफी मूर्ख) व्यवहार को ठीक करने का अवसर लिया है। यह हर अब और फिर जांचने के लिए पर्याप्त होना चाहिए, प्रत्येक delete पर नहीं। फिक्स वी 8 6.0 में होगा, जिसे कुछ महीनों में नोड द्वारा उठाया जाना चाहिए (मुझे विश्वास है कि नोड 8 इसे किसी बिंदु पर प्राप्त करना है)।

कहा कि, delete, विभिन्न रूपों और कई स्थितियों में मंदी के परिमाण का कारण बनता है, क्योंकि यह बातें और अधिक जटिल बनाने के लिए जाता है का उपयोग कर, और अधिक जांच करने और/या विभिन्न तेजी से पथ होकर गिरते इंजन (किसी भी इंजन) के लिए मजबूर । आमतौर पर जब भी संभव हो delete का उपयोग करने से बचने के लिए अनुशंसा की जाती है। चूंकि आपके पास ES6 मानचित्र/सेट हैं, इसलिए उनका उपयोग करें! :-)

+0

धन्यवाद! मुझे लगता है कि यह पूरी चीज को स्पष्ट करता है :) – user3031051

1

प्रश्न का उत्तर देने है "क्यों एन 1 जोड़ने हटाने आपरेशन धीमा कर देती है"

मेरा अनुमान है:। सुस्ती तरह से स्मृति अपने Object के लिए आवंटित किया जाता है से आता है।

इस के लिए अपने कोड को बदलने का प्रयास करें:, अब

(() => { 
    const N = 50855 

    const o = {} 
    for (let i = 0; i < N; i++) { 
     o[i] = i 
    } 

    // Show the heap memory allocated 
    console.log(process.memoryUsage().heapTotal); 
    const t1 = Date.now() 
    for (let i = 0; i < N; i++) { 
     delete o[i] 
    } 
    const t2 = Date.now() 

    console.log(N/(t2 - t1) + ' OP/S') 
})(); 

जब आप N = 50855 के साथ चलाने के स्मृति आवंटित है: "8,306,688 बाइट्स" (8.3MB)

आप N = 50855 साथ समाप्त हो जाता है स्मृति आवंटित है: "8,929,280 बाइट्स" (8.9MB)।

तो आपको 600kb आवंटित स्मृति के आकार में वृद्धि हुई है, केवल आपके ऑब्जेक्ट में एक और कुंजी जोड़कर।

अब, मैं कहता हूँ कि मैं "अनुमान" है कि इस जगह है जहाँ सुस्ती से आते हैं, लेकिन मुझे लगता है यह भावना हटाने समारोह अपने वस्तु के आकार में वृद्धि के रूप में धीमी होने के लिए बनाता है।

यदि आप N = 70855 के साथ प्रयास करते हैं तो आपके पास अभी भी 8.9MB उपयोग किया जाएगा। ऐसा इसलिए होता है क्योंकि आम तौर पर स्मृति आवंटन उनके द्वारा किए गए स्मृति आवंटन की संख्या को कम करने के लिए एक ऐरे/ऑब्जेक्ट के आकार को बढ़ाने के दौरान निश्चित "बैचों" में स्मृति आवंटित करते हैं।

अब, एक ही बात delete और GC साथ हो सकता है। स्मृति आप हटाना जीसी द्वारा उठाया जाना है, और अगर वस्तु आकार बड़ा है GC धीमी हो जाएगा। यदि कुंजी की संख्या किसी विशिष्ट संख्या के अंतर्गत जाती है तो स्मृति भी जारी की जा सकती है।

(आप गतिशील सरणियों के लिए स्मृति आवंटन के बारे में पढ़ना चाहिए यदि आप और अधिक जानना चाहते हैं, क्या वृद्धि दर आप स्मृति आवंटन के लिए इस्तेमाल करना चाहिए पर एक शांत लेख था, मैं इसे एटीएम :(नहीं मिल सकता है)

पुनश्च:।। delete "बेहद धीमी गति से",

+0

धन्यवाद, संपादित कोड स्निपलेट ओपी/एस => केओपी/एस। लेकिन यह इतना महत्वपूर्ण नहीं है। X300-400 प्रदर्शन गिरावट है। मुझे लगता है कि समस्या वी 8 में वस्तुओं के स्मार्ट कार्यान्वयन में बस बग है। या हो सकता है कि वी 8 लेखकों को ऑब्जेक्ट्स का उपयोग करने के बजाय हैशटेबल्स पहले से ही ईएस 6 मानचित्र का उपयोग करें! यह 2K17 है :) – user3031051

संबंधित मुद्दे

 संबंधित मुद्दे