Java同步块在Node中的等效



我试图限制一个方法,所以一次只能运行一个承诺。

//Method that should only allow one promise at a time
async myMethod(obj: MyObj):Promise<MyObj>{
const canInsert = await this.DbChecks();
if(canInsert === true){
return this.insert(obj)
}
}

我知道这个问题已经被问过了,Node是单线程的,但是这个方法做了一个db请求来检查它是否应该运行插入,如果另一个承诺同时改变了db记录,它会使第一个承诺的检查错误。

解决这个问题而不是等待的方法是创建一个承诺队列,一旦每个承诺完成(或超时),队列中最早的承诺将被弹出(如果存在)。当一个承诺即将被评估时,你可以把它推到承诺队列的末尾,这样你就能实现一次只运行一个承诺的预期行为。

这是我的一个基于承诺的互斥锁的实现:

let promises = [];
async function getLock() {
let resolver;
let lock = new Promise(done => {
resolver = () => {
promises.shift();
done();
}
});
promises.push(lock);
// If there's more than one promise in the queue
// force caller to wait:
if (promises.length > 1) {
await promises[0];
}

return {
release: resolver
};
}
module.exports = {
getLock
}

你可以这样使用:

async myMethod(obj: MyObj):Promise<MyObj>{
const lock = await getLock(); // prevent other code from executing this
const canInsert = await this.DbChecks();
if(canInsert === true){
return this.insert(obj)
}
lock.release();
}

这个想法其实很简单。每次对getLock()的调用都会将自己的promise插入到一个队列(promises数组)中,这个队列管理调用调度的顺序。

队列中的promise只有在队列中只有一个promise时才返回。所以第一个调用它的函数得到一个承诺,但是如果另一个函数调用它,它将不得不等待。调用lock.release()将自己从队列中移除,允许下一个调用返回承诺。

这是一个非常简单的互斥锁实现,全局只有一个互斥锁。您可以通过使用某种ID来分隔每个互斥锁的承诺队列(promises数组)来修改它以支持多个互斥锁:

let promises = {};

:

async function getLock(id) { ...

并按需创建promises数组:

if (promises[id] === undefined) {
promises[id] = [];
}

尽量不要限制你的功能。

我知道这在某些情况下可能很有用,但如果你将代码部署到生产环境中,并且有多个应用程序实例在运行,那么你将需要在变量中使用多个队列。这通常不是问题,因为很多数据库都是ACID兼容的(同时运行多个操作是安全的),所以如果你正在使用的数据库是兼容的,那么希望你不需要担心这个。

2。实现队列/限制机制

就像我在第一种方式中所说的,这不会有太大的影响,这取决于您部署代码的方式。这仍然是一个好主意,如果你想减少负载或使并发更容易,我认为最好的方法是在slebetman的答案:https://stackoverflow.com/a/68537409/12426277。

最新更新