Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance considerations with `Promise.all` and a large amount of asynchronous operations

When using Promise.all with asynchronous code (in case of synchronous code, there is nothing to worry about), you can suffer from severe performance (if not other kinds of) issues, when you want to send out a whole bunch (be it tens, hundreds, thousands or even millions) of requests, given the receiving end of your asynchronous operations (e.g. the local filesystem, an HTTP server, a database, etc etc.) does not gracefully handle that many parallel requests.

For that case, it would be perfect if we could tell Promise.all up to how many promises we want to have in-flight simultaneously. However, since A+ is supposed to be lean, adding these sorts of fancy features would certainly not make sense.

So what would be a better way of achieving this?

like image 1000
Domi Avatar asked Apr 18 '15 19:04

Domi


People also ask

Do async methods that await a non-completed task affect performance?

A performance overhead of async methods that await non-completed task is way more substantial (~300 bytes per operation on x64 platform). And, as always, measure first. If you see that an async operation causes a performance problem, you may switch from Task<T> to ValueTask<T>, cache a task or make a common execution path synchronous if possible.

How can I improve the performance of my asynchronous code?

But you may also try to make your async operations coarser grained. This can improve performance, simplify debugging and overall make your code easier to reason. Not every small piece of code has to be asynchronous.

How many concurrent workers do we need for asynchronous operations?

However big the number of asynchronous operations we wish to perform, we will ever need at most, 3 concurrent workers. We will then want to give a way to our workers to retrieve the next resource identifier, or thing, to perform the asynchronous operation from.

Is ~all the asynchronous operations performed concurrently in JavaScript?

As we can see, ~all the asynchronous operations were performed concurrently, and sometimes, that's perfectly fine and exactly what we want. Note: Promise.all only waits for all the Promises to be resolved. The actual asynchronous operation is triggered by the function call from Array.prototype.map, creating a new Promise on each call.


1 Answers

Well, first of all - it's impossible to give a concurrency argument to Promise.all since promises represent already started operations so you cannot queue them or make the wait before executing.

What you want to perform with limited concurrency is promise returning functions. Lucky for you - bluebird ships with this feature (As of version 2.x) using Promise.map:

 Promise.map(largeArray, promiseReturningFunction, {concurrency: 16});

The concurrency parameter decides how many operations may happen at once - note that this is not a global value - but only for this chain. For example:

Promise.map([1,2,3,4,5,6,7,8,9,10], function(i){
    console.log("Shooting operation", i);
    return Promise.delay(1000);
}, {concurrency: 2});

Fiddle

Note that execution order is not guaranteed.

like image 111
Benjamin Gruenbaum Avatar answered Sep 21 '22 03:09

Benjamin Gruenbaum