javascript - Promise.all मेरे सभी रैम का उपभोग करता है



node.js bluebird (1)

मुझे एक एपीआई के लिए एक दर सीमक मिला है जिसका मैं उपयोग कर रहा हूं जो प्रति सेकंड 20 अनुरोधों की अनुमति देता है। सभी अनुरोधों के आधार पर वादा किया जाता है और एक बार जब कोई प्रतिक्रिया होती है तो यह वादा एपीआई डेटा के साथ हल किया जाएगा।

समस्या:

मैंने एक वादा सेटअप किया है जिसमें 58k वादे हैं जो सभी की प्रतिक्रिया की प्रतीक्षा कर रहे हैं। इसलिए धीरे-धीरे मेमोरी बढ़ रही है जब तक कि मैं मेमोरी से बाहर नहीं निकल रहा हूं। मेरी विशिष्ट स्थिति में मुझे अपने then() और then() तक डेटा को पास करने की आवश्यकता नहीं है, और डेटा मेरे सभी रैम को खा रहा है।

कोड:

  }).then(() => {
    // 2. Crawl for all clanprofiles from these leaderboards
    const promiseArray = []
    for (let i = 0; i < clanTags.length; i++) {
      // Resolved data from getClanProfile() is eating up all my RAM
      const p = backgroundScheduler.getClanProfile(clanTags[i], true)
      promiseArray.push(p)
    }
    return Promise.all(promiseArray)
  }).then(() => {

तो क्या वायदा करने का एक तरीका है जब तक कि वादाअरे हल किए गए डेटा की आवश्यकता के बिना हल नहीं हो जाता?


यदि आप कभी 58k वादे, उनके संबद्ध async संचालन और उनके परिणाम डेटा को एक बार में सक्रिय नहीं करते हैं तो आप कम मात्रा में मेमोरी का उपयोग करेंगे।

इसके बजाय आप एक बार में एक्स ऑपरेशन चलाना चाहते हैं और जब एक खत्म हो जाता है, तो आप अगले एक ही समय में एक्स से अधिक उड़ान में कभी नहीं के साथ शुरू करते हैं और कभी भी एक बार में एक्स से अधिक वादे नहीं करते हैं।

आप X के एक उचित मूल्य के साथ प्रयोग कर सकते हैं। 1 का मान अनुक्रमिक संचालन है, लेकिन आप अक्सर एक्स के कुछ उच्च मूल्य का उपयोग करके समग्र अंत-टू-एंड ऑपरेशन समय में सुधार कर सकते हैं। यदि सभी अनुरोध एक ही मेजबान को मार रहे हैं, तो X है शायद 5-10 से अधिक नहीं (चूंकि दिए गए होस्ट वास्तव में एक बार में बहुत सारी चीजें नहीं कर सकते हैं और इसे अधिक से अधिक करने के लिए कह सकते हैं, एक बार में इसे धीमा कर सकते हैं)।

यदि प्रत्येक अनुरोध एक अलग होस्ट के लिए है, तो आप एक्स को उच्च बनाने में सक्षम हो सकते हैं। प्रयोग आपको शिखर मेमोरी उपयोग और समग्र थ्रूपुट दोनों के लिए एक इष्टतम मूल्य देगा और कुछ हद तक आपकी विशिष्ट परिस्थितियों पर निर्भर करता है।

Bluebird's Promise.map() पास एक संगोष्ठी विकल्प है जो आपके लिए ऐसा करेगा, लेकिन एक ही समय में उड़ान में केवल X के लिए कोड करने के कई तरीके भी हैं।

एक बार में उड़ान में कितने हैं, यह प्रबंधित करने के कुछ अन्य कोडिंग उदाहरण यहां दिए गए हैं:

एक एपीआई के लिए कई अनुरोध करें जो केवल 20 अनुरोध को एक मिनट में संभाल सकता है

श्रृंखला में वादों को कैसे निष्पादित करें?

स्मृति से बाहर होने के कारण वादे पूरे करने में असमर्थ

एक बार में 1,000,000 अनुरोध 100 आग दें

इसे कैसे बनाया जाए ताकि मैं एपीआई कॉल पर दर सीमा को रोकने के लिए जावास्क्रिप्ट में एक बार में 10 वादों को निष्पादित कर सकूं?

यदि आपको हल किए गए डेटा की आवश्यकता नहीं है, तो आप इसे इस तरह बदलकर जल्द ही GCed होने की अनुमति दे सकते हैं:

  const p = backgroundScheduler.getClanProfile(clanTags[i], true).then(data => {
      return 0;     // make resolved value just be a simple number
                    // so other data is now eligible for GC
  });
  promiseArray.push(p)    

और, यहां एक सरल कार्यान्वयन है जो एक ही समय में उड़ान में एक्स अनुरोधों से अधिक नहीं के साथ एक सरणी को पुन: प्रसारित करता है:

// takes an array of items and a function that returns a promise
// runs no more than maxConcurrent requests at once
function mapConcurrent(items, maxConcurrent, fn) {
    let index = 0;
    let inFlightCntr = 0;
    let doneCntr = 0;
    let results = new Array(items.length);
    let stop = false;

    return new Promise(function(resolve, reject) {

        function runNext() {
            let i = index;
            ++inFlightCntr;
            fn(items[index], index++).then(function(val) {
                ++doneCntr;
                --inFlightCntr;
                results[i] = val;
                run();
            }, function(err) {
                // set flag so we don't launch any more requests
                stop = true;
                reject(err);
            });
        }

        function run() {
            // launch as many as we're allowed to
            while (!stop && inflightCntr < maxConcurrent && index < items.length) {
                runNext();
            }
            // if all are done, then resolve parent promise with results
            if (doneCntr === items.length) {
                resolve(results);
            }
        }

        run();
    });
}




bluebird