2016-05-13 10 views
7

Ho una matrice che contiene una serie di promesse e ogni array interno potrebbe avere promesse 4k, 2k o 500.Esegui batch di promesse in serie. Una volta che Promise.all è finito vai al lotto successivo

In totale ci sono circa 60k promesse e posso provarlo con altri valori.

ora ho bisogno di eseguire il Promise.all (BigArray [0]).

Una volta che il primo array interno è fatto, ho bisogno di eseguire la successiva Promise.all (BigArray [1]), e così via e così via.

Se provo ad eseguire un Promise.all (BigArray) il suo lancio:

allocazione fatale errore call_and_retry_2 fallito - processo di memoria ho bisogno di eseguirlo ciascuna delle promesse in serie, non in parallelo, che mi penso che sia ciò che fa Node. Non dovrei usare nuove librerie, tuttavia sono disposto a considerare la risposta !.

Edit:

Ecco un pezzo esempio di codice:

function getInfoForEveryInnerArgument(InnerArray) { 
    const CPTPromises = _.map(InnerArray, (argument) => getDBInfo(argument)); 
    return Promise.all(CPTPromises) 
     .then((results) => { 
      return doSomethingWithResults(results); 
     }); 
} 
function mainFunction() { 
    BigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; 
    //the summ of all arguments is over 60k... 
    const promiseArrayCombination = _.map(BigArray, (InnerArray, key) => getInfoForEveryInnerArgument(InnerArray)); 

    Promise.all(promiseArrayCombination).then((fullResults) => { 
     console.log(fullResults); 
     return fullResults; 
    }) 
} 
+0

Sei lo stesso utente che ha postato questa domanda precedente che contiene un contesto pertinente: [Esegui Promise.all in serie] (http://stackoverflow.com/questions/37196699/execute-promise-all-in-series/37196780# comment61956748_37196780)? – jfriend00

+0

Stai bene con tutte le operazioni a 60k eseguite in parallelo, ma vuoi solo processare i risultati in serie (un sotto-array alla volta)? Oppure, hai effettivamente bisogno delle operazioni che ogni sottoarray rappresenta per essere eseguito in serie e processato in serie? Quest'ultimo sarebbe molto più sicuro da un punto di vista della memoria e delle risorse in node.js. – jfriend00

+0

Sì, lo sono. Ho bisogno che funzionino in serie. sto bene con solo le promesse innerArray in esecuzione in parallelo. Una volta che innerArray 1 è terminato, passa alle prossime promesse da 500-4k su innerArray 2 ed esegui quelle in parallelo, una volta che le promesse di innnerArray 500-4k sono state eseguite, passa a innerArray 3 e fai quei 500-4k, una volta che innerArray 3 è stato fatto mossa su innerArray 4 e fare quei 500-4k ... e così via – user1554966

risposta

6

La tua domanda è un po 'misnamed che può aver confuso alcune persone in questa domanda e nella versione precedente di questa domanda. Si sta tentando di eseguire un batch di operazioni asincrone in serie, un batch di operazioni, quindi quando viene eseguito, eseguire un altro batch di operazioni. I risultati di quelle operazioni asincrone sono tracciati con promesse. Le promesse stesse rappresentano operazioni asincrone che sono già state avviate. Le "promesse" non vengono eseguite da sole. Quindi tecnicamente, non "esegui una serie di promesse in serie". Esegui una serie di operazioni, traccia i loro risultati con promesse, quindi esegui il batch successivo quando il primo lotto viene completato.

In ogni caso, ecco una soluzione per serializzare ogni lotto di operazioni.

È possibile creare una funzione interna che di solito chiamo next() che permette di elaborare ogni iterazione. Quando la promessa si risolve dalla lavorazione un innerArray, si chiama di nuovo next():

function mainFunction() { 
    return new Promise(function(resolve, reject) { 
     var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; 
     //the summ of all arguments is over 60k... 
     var results = []; 

     var index = 0; 
     function next() { 
      if (index < bigArray.length) { 
       getInfoForEveryInnerArgument(bigArray[index++]).then(function(data) { 
        results.push(data); 
        next(); 
       }, reject); 
      } else { 
       resolve(results); 
      } 
     } 
     // start first iteration 
     next(); 
    }); 
} 

raccoglie Questo anche tutti i sotto-risultati in una matrice di risultati e restituisce una promessa maestro che ha risolto il valore è questo si traduce array.Quindi, è possibile utilizzare questo tipo:

mainFunction().then(function(results) { 
    // final results array here and everything done 
}, function(err) { 
    // some error here 
}); 

È anche possibile utilizzare il modello di .reduce() progetto per iterare una matrice in serie:

function mainFunction() { 
    var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; 
    return bigArray.reduce(function(p, item) { 
     return p.then(function(results) { 
      return getInfoForEveryInnerArgument(item).then(function(data) { 
       results.push(data); 
       return results; 
      }) 
     }); 
    }, Promise.resolve([])); 
} 

Questo crea più promesse simultanee rispetto alla prima opzione e ho Non so se questo è un problema per un così grande insieme di promesse (è per questo che ho offerto l'opzione originale), ma questo codice è più pulito e il concetto è conveniente da usare anche in altre situazioni.


FYI, ci sono alcune funzionalità aggiuntive promesse create per fare questo per voi. Nella Bluebird promise library (che è una grande libreria per sviluppo utilizzando promesse), hanno Promise.map() che è fatto per questo:

function mainFunction() { 
    var bigArray = [[argument1, argument2, argument3, argument4], [argument5, argument6, argument7, argument8], ....]; 
    return Promise.map(bigArray, getInfoForEveryInnerArgument); 

} 
0

Si può fare in modo ricorsivo, per esempio qui avevo bisogno di mettere circa 60k documenti in mongo, ma era troppo grande, di farlo in un solo passo, quindi prendo documenti 1k, inviarli al mongo, dopo che è finito mi prendo un altro documenti 1k ecc

exports.rawRecursive = (arr, start) => { 
     //ending condition 
     if (start > arr.length) { 
      return; 
     } 

     Rawmedicament.insertManyAsync(_.slice(arr, start, start + 1000)).then(() => { 
      //recursive 
      exports.rawRecursive(arr, start + 1000); 
     }); 
}; 

Se si vuole notare, quando tutto è fatto , puoi in condizioni di fine chiamata di richiamo o se ti piacciono le Promesse puoi chiamare resolve() lì.

0

Inoltre, se il vettore originale è non di promesse ma di oggetti che devono essere trattati, lotto lavorazione può essere fatto senza dipendenza esterna mediante combinazione di Array.prototype.map(), Array.prototype.slice() e Promise.all():

// Main batch parallelization function. 
 
function batch(tasks, pstart, atonce, runner, pos) { 
 
    if (!pos) pos = 0; 
 
    if (pos >= tasks.length) return pstart; 
 
    var p = pstart.then(function() { 
 
    output('Batch:', pos/atonce + 1); 
 
    return Promise.all(tasks.slice(pos, pos + atonce).map(function(task) { 
 
     return runner(task); 
 
    })); 
 
    }); 
 
    return batch(tasks, p, atonce, runner, pos + atonce); 
 
} 
 

 
// Output function for the example 
 
function output() { 
 
    document.getElementById("result").innerHTML += Array.prototype.slice.call(arguments).join(' ') + "<br />"; 
 
    window.scrollTo(0, document.body.scrollHeight); 
 
} 
 

 
/* 
 
* Example code. 
 
* Note: Task runner should return Promise. 
 
*/ 
 
function taskrunner(task) { 
 
    return new Promise(function(resolve, reject) { 
 
    setTimeout(function() { 
 
     output('Processed:', task.text, 'Delay:', task.delay); 
 
     resolve(); 
 
    }, task.delay); 
 
    }); 
 
} 
 

 
var taskarray = []; 
 
function populatetasks(size) { 
 
    taskarray = []; 
 
    for (var i = 0; i < size; i++) { 
 
    taskarray.push({ 
 
     delay: 500 + Math.ceil(Math.random() * 50) * 10, 
 
     text: 'Item ' + (i + 1) 
 
    }); 
 
    } 
 
} 
 

 
function clean() { 
 
    document.getElementById("result").innerHTML = ''; 
 
} 
 

 
var init = Promise.resolve(); 
 
function start() { 
 
    var bsize = parseInt(document.getElementById("batchsize").value, 10), 
 
    tsize = parseInt(document.getElementById("taskssize").value, 10); 
 
    populatetasks(tsize); 
 
    init = batch(taskarray.slice() /*tasks array*/ , init /*starting promise*/ , bsize /*batch size*/ , taskrunner /*task runner*/); 
 
}
<input type="button" onclick="start()" value="Start" /> 
 
<input type="button" onclick="clean()" value="Clear" />&nbsp;Batch size:&nbsp; 
 
<input id="batchsize" value="4" size="2"/>&nbsp;Tasks:&nbsp; 
 
<input id="taskssize" value="10" size="2"/> 
 
<pre id="result" />

+0

Vedere la [prima modifica] (http://stackoverflow.com/revisions/40850909/1) per la versione non ricorsiva di 'batch'. – Annarfych