Node JS并发处理编码面试问题



我参加了一次NodeJS编码面试。下面的代码从不同的浏览器异步执行(假设(。如果ID更新相同,但从不同的地方调用(比如浏览器(,我们的解决方案需要锁定函数的执行。然后释放锁以执行下一个请求。

这里没有对下面提到的代码进行任何更改。

async function update(id, data) {
console.log(`start --> id:${id}, data:${data}`);
await randomDelay(); //update is happening here
console.log(`end --> id:${id}, data:${data}`);
}
//=============================================================================
//================= Don't change anything below ===============================
//=============================================================================
//---- update() is getting called from many places ----
update(1, "browser 1");
update(1, "browser 2");
//========================= Utility functions ===================================
//========================= Don't change any here================================
async function sleep(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), ms);
});
}
async function randomDelay() {
const randomTime = Math.round(Math.random() * 1000);
return sleep(randomTime);
}

这将产生如下输出。

start --> id:1, data:browser 1
start --> id:1, data:browser 2
end --> id:1, data:browser 1
end --> id:1, data:browser 2

预期的答案是

start --> id:1, data:browser 1
end --> id:1, data:browser 1
start --> id:1, data:browser 2
end --> id:1, data:browser 2

请注意代码"中的注释;不要更改下面的任何内容;。可能的解决方案是什么?

您可以使用由ID键控的队列的哈希表,这样只有具有相同ID的作业才能连续运行,否则它们将并发运行。

let hash = {};
class Queue {
constructor() {
this.isBusy = false;
this.jobs = [];
}
push(jobFn) {
return new Promise((resolve) => {
this.jobs.push({
jobFn,
resolve
});
this.next();
});
}
next() {
if (this.isBusy || this.jobs.length === 0) return;
this.isBusy = true;
let currJob = this.jobs.shift();
return currJob.jobFn().then((data) => {
currJob.resolve(data);
this.isBusy = false;
this.next();
});
}
}
async function update(id, data) {
const updateFn = async () => {
console.log(`start --> id:${id}, data:${data}`);
await randomDelay(); //update is happening here
console.log(`end --> id:${id}, data:${data}`);
};
if (id in hash) {
hash[id].push(updateFn);
} else {
hash[id] = new Queue(updateFn);
hash[id].push(updateFn);
}
}
//=============================================================================
//================= Don't change anything below ===============================
//=============================================================================
//---- update() is getting called from many places ----
update(1, "browser 1");
update(1, "browser 2");
update(2, "browser 1");
update(2, "browser 2");
update(1, "browser 3");
update(1, "browser 4");
//========================= Utility functions ===================================
//========================= Don't change any here================================
async function sleep(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), ms);
});
}
async function randomDelay() {
const randomTime = Math.round(Math.random() * 1000);
return sleep(randomTime);
}

此解决方案仅适用于具有不同数据的twoconsecuence调用,正如您所期望的,因此我正在对其进行扩展,但目前,我希望它能让您对如何实现有一个很好的了解

const callStack = []
async function update(id, data) {
const stackLen = callStack.length;
let currentIndex;
if (stackLen) {
let currentCall = callStack[stackLen - 1];
if (currentCall.start == true && currentCall.await == true) {
setImmediate(() => update(id, data))
return;
}
currentIndex = stackLen - 1;
if (currentCall.args[0] == id && currentCall.args[1] !== data) {

if (currentCall.await === true) {
currentCall.start = true;
update(id, data)
return;
}
}
} else {
callStack.push({ args: [...arguments], await: true })
currentIndex = 0;
}
console.log(`start --> id:${id}, data:${data}`);
await randomDelay(); //update is happening here
console.log(`end --> id:${id}, data:${data}`);
callStack[currentIndex].await = false;
}

最新更新