javascript - Promise.all consume toda mi RAM
node.js bluebird (1)
Utilizará una cantidad menor de memoria si nunca tiene 58k promesas, sus operaciones asíncronas asociadas y sus datos de resultados activos a la vez.
En cambio, desea ejecutar operaciones X de una vez y luego, cuando finalice, comience la siguiente con nunca más de X en vuelo al mismo tiempo y nunca más de X promesas en uso a la vez.
Puede experimentar con un valor apropiado de X. Un valor de 1 son operaciones secuenciales, pero a menudo puede mejorar el tiempo total de operación de extremo a extremo utilizando un valor mayor de X. Si todas las solicitudes llegan al mismo host, entonces X es probablemente no más de 5-10 (ya que un host determinado no puede hacer muchas cosas a la vez y pedirle que haga más de lo que puede hacer a la vez solo lo ralentiza).
Si cada solicitud es a un host diferente, entonces puede hacer que X sea más alto. La experimentación le daría un valor óptimo tanto para el uso máximo de memoria como para el rendimiento general y, en cierta medida, depende de sus circunstancias específicas.
Promise.map()
Bluebird tiene una opción de concurrencia que lo hará por usted, pero también hay numerosas formas de codificar solo X en vuelo al mismo tiempo.
Estos son algunos otros ejemplos de codificación para administrar cuántos están en vuelo a la vez:
Realice varias solicitudes a una API que solo puede manejar 20 solicitudes por minuto
¿Cómo ejecutar promesas en serie?
incapaz de completar promesas por falta de memoria
Dispara 1,000,000 de solicitudes 100 a la vez
Si no necesita los datos resueltos, puede permitir que se GCed antes reemplazándolos así:
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)
Y, aquí hay una implementación simple que itera una matriz con no más de X solicitudes en vuelo al mismo tiempo:
// 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();
});
}
Tengo un limitador de velocidad para una API que estoy usando que permite 20 solicitudes por segundo. Todas las solicitudes se basan en promesas y la promesa se resolverá con los datos de la API una vez que haya una respuesta.
El problema:
Configuré un array de promesas que contiene 58k promesas, todas esperando una respuesta.
Lentamente, la memoria aumenta hasta que me estoy quedando sin memoria.
En mi situación específica, no necesito pasar los datos resueltos a mi
then()
y los datos están consumiendo toda mi RAM.
El código:
}).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(() => {
Entonces, ¿hay alguna manera de esperar hasta que se resuelva la promesa Array sin necesitar los datos resueltos?