[英]How can I limit Q promise concurrency?
How do I write a method that limits Q promise concurrency? 如何编写限制Q promise并发的方法?
For instance, I have a method spawnProcess
. 例如,我有一个方法
spawnProcess
。 It returns a Q promise. 它返回一个Q承诺。
I want no more than 5 process spawned at a time, but transparently to the calling code. 我希望一次生成的进程不超过5个,但对调用代码透明。
What I need to implement is a function with signature 我需要实现的是一个带签名的函数
function limitConcurrency(promiseFactory, limit)
that I can call like 我可以这样打电话
spawnProcess = limitConcurrency(spawnProcess, 5);
// use spawnProcess as usual
I already started working on my version, but I wonder if anyone has a concise implementation that I can check against. 我已经开始研究我的版本,但我想知道是否有人有一个我可以检查的简洁实现。
I have a library that does this for you https://github.com/ForbesLindesay/throat 我有一个库为你做这个https://github.com/ForbesLindesay/throat
You can use it via browserify or download the standalone build from brcdn ( https://www.brcdn.org/?module=throat&version=latest ) and add it as a script tag. 您可以通过browserify使用它或从brcdn( https://www.brcdn.org/?module=throat&version=latest )下载独立版本并将其添加为脚本标记。
Then (assuming the Promise
constructor is polyfilled or implemented in your environment) you can do: 然后(假设
Promise
构造函数是polyfilled或在您的环境中实现),您可以:
//remove this line if using standalone build
var throat = require('throat');
function limitConcurrency(promiseFactory, limit) {
var fn = throat(promiseFactory, limit);
return function () {
return Q(fn.apply(this, arguments));
}
}
You could just call throat(promiseFactory, limit)
directly but that would return a promise promise rather than a Q promise. 你可以直接调用
throat(promiseFactory, limit)
,但这会返回一个promise promise而不是一个Q promise。
I also really like using it with array.map. 我也非常喜欢将它与array.map一起使用。
// only allow 3 parallel downloads
var downloadedItems = Q.all(items.map(throat(download, 3)));
This seems to be working for me. 这似乎对我有用。
I'm not sure if I could simplify it. 我不确定我是否可以简化它。 The recursion in
scheduleNextJob
is necessary so the running < limit
and limit++
always execute in the same tick. scheduleNextJob
的递归是必要的,因此running < limit
和limit++
总是在相同的tick中执行。
Also available as a gist. 也可作为要点。
'use strict';
var Q = require('q');
/**
* Constructs a function that proxies to promiseFactory
* limiting the count of promises that can run simultaneously.
* @param promiseFactory function that returns promises.
* @param limit how many promises are allowed to be running at the same time.
* @returns function that returns a promise that eventually proxies to promiseFactory.
*/
function limitConcurrency(promiseFactory, limit) {
var running = 0,
semaphore;
function scheduleNextJob() {
if (running < limit) {
running++;
return Q();
}
if (!semaphore) {
semaphore = Q.defer();
}
return semaphore.promise
.finally(scheduleNextJob);
}
function processScheduledJobs() {
running--;
if (semaphore && running < limit) {
semaphore.resolve();
semaphore = null;
}
}
return function () {
var args = arguments;
function runJob() {
return promiseFactory.apply(this, args);
}
return scheduleNextJob()
.then(runJob)
.finally(processScheduledJobs);
};
}
module.exports = {
limitConcurrency: limitConcurrency
}
I wrote a little library to do this: https://github.com/suprememoocow/qlimit 我写了一个小库来做到这一点: https : //github.com/suprememoocow/qlimit
It's extremely easy to use and is specifically designed to work with Q promises: 它非常易于使用,专门用于Q承诺:
var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency
// Using the same example as above
return Q.all(items.map(limit(function(item, index, collection) {
return performOperationOnItem(item);
}));
It can also be used to limit concurrency to a specific resource, like this: 它还可以用于限制特定资源的并发性,如下所示:
var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency
var fetchSomethingFromEasilyOverwhelmedBackendServer = limit(function(id) {
// Emulating the backend service
return Q.delay(1000)
.thenResolve({ hello: 'world' });
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.