It could be probably added as a `Promise.all(iterable, concurrency?)` Some existing implementations: - http://bluebirdjs.com/docs/api/promise.map.html - https://caolan.github.io/async/v3/docs.html#mapLimit - I tried to write one: https://github.com/caub/misc/blob/master/utils/promise-concurrent.js
On Fri, Sep 6, 2019 at 8:33 PM Tom Boutell <[email protected]> wrote: > I am more interested in syntax two than syntax one, which I felt should > probably be included for completeness. But hey, as you say, maybe not since > unguarded concurrency is indeed usually a mistake. > > Taken on its own, do you have an objection to `for (item of items > concurrency 5) { ... }`? > > > On Fri, Sep 6, 2019 at 1:46 PM C. Scott Ananian <[email protected]> > wrote: > >> The current way to write what you want is: >> >> await Promise.all(itemsCursor.map(item => db.insert(item)); >> >> or >> >> await Promise.all(itemsCursor.map(Promise.guard(5, item => >> db.insert(item)))); >> >> if you are using a library like `prfun` ( >> https://github.com/cscott/prfun#promiseguardfunctionnumber-condition-function-fn--function >> ). >> >> I'm not sure adding a new parallel loop construct is an obvious >> improvement on this, especially since unguarded concurrent execution is >> usually a mistake (can cause memory requirements to blow up), as you point >> out yourself. >> >> I'd be more in favor of new syntax if it was integrated with a >> work-stealing mechanism, since (a) that can't as easily be done in a >> library function (you need access to the entire set of runnable tasks, not >> just the ones created in this loop), and (b) is more likely to be >> correct/fast by default and not lead to subtle resource-exhaustion problems. >> --scott >> >> On Fri, Sep 6, 2019 at 12:40 PM Tom Boutell <[email protected]> >> wrote: >> >>> *Specifying concurrency for "for...of" loops potentially containing >>> "await" statements in the loop body* >>> >>> In the async/await era, I see most developers using the async and await >>> keywords in 90% of situations, shifting to "Promise.all" or the bluebird >>> library only to cope with concurrency issues. >>> >>> The most common case in my experience is the need to admit a manageable >>> level of parallelism when iterating a large array (or iterator, see the >>> final section) and performing asynchronous work on each item. Unlimited >>> concurrency (Promise.all) tends to overwhelm backends involved in a way >>> that confuses developers as to what is happening. Bluebird's "Promise.map" >>> permits concurrency to be specified, which is great, but requires pulling >>> in a library and switching of mental gears ("OK right, these async >>> functions return promises," etc). >>> >>> To build on the friendliness of async/await, I propose these two >>> syntaxes be accepted: >>> >>> SYNTAX ONE >>> >>> ```js >>> for (item of items concurrent) { >>> // db.insert is an async function >>> await db.insert(item); >>> } >>> ``` >>> >>> In Syntax One, all loop bodies commence concurrently (see below for the >>> definition of "concurrently" with regard to async). If an exception is not >>> caught inside the loop, it is thrown beyond the loop, and all exceptions >>> subsequently thrown by concurrently executing loop bodies are discarded >>> (like Promise.all). >>> >>> *While I feel that unlimited concurrency is usually a mistake in a >>> situation where you have an array of items of unpredictable number, it >>> seems odd not to have a syntax for this case, and "concurrency 0" seems >>> clunky.* >>> >>> SYNTAX TWO >>> >>> ```js >>> for (item of items concurrency 5) { >>> // db.insert is an async function >>> await db.insert(item); >>> } >>> ``` >>> >>> in Syntax Two, up to 5 loop bodies commence concurrently (see below). >>> There is no guarantee that item 3 will finish before item 2, or that item 4 >>> won't start (due to 3 being finished) before item 2 ends, etc. If an >>> exception is not caught inside the loop, it is thrown beyond the loop, and >>> all exceptions subsequently thrown by concurrently executing loop bodies >>> are discarded (like Promise.all in this respect, except for the restriction >>> of concurrency). >>> >>> DEFINING CONCURRENCY FOR ASYNC >>> >>> For purposes of this proposal, "concurrent" execution means that >>> multiple loop bodies may be suspended via "await" at any given time. It >>> does NOT refer to multithreaded execution, worker threads, etc. >>> >>> CONSIDERATIONS FOR ASYNC ITERATORS >>> >>> Async iterator syntax for "for...of" loops, as in: >>> >>> ```js >>> for await (item of itemsCursor) { ... } >>> ``` >>> >>> Should also support concurrency for the loop body, with the same syntax: >>> >>> ```js >>> for await (item of itemsCursor concurrency 5) { ... } >>> ``` >>> >>> *It is important to note that this syntax does not add concurrency to >>> the async iterator itself, *at least not at this time, as I believe the >>> interface for defining async iterators does not currently accommodate this. >>> However this syntax is still useful because it *fetches the items >>> sequentially from the iterator, but may "fill the hopper" with up to five >>> iterator results* that are currently being actively processed by loop >>> bodies. In many cases, fetching items via an iterator is much faster than >>> the processing that will be done to them in the loop bodies, and so this is >>> still useful. >>> >>> Thanks for reading! >>> >>> -- >>> Chief Software Architect >>> Apostrophe Technologies >>> Pronouns: he / him / his >>> _______________________________________________ >>> es-discuss mailing list >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> > > -- > Chief Software Architect > Apostrophe Technologies > Pronouns: he / him / his > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

