Node JS并发处理编码面试题
Node JS Concurrency Handling Coding Interview Question
我参加了 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
请注意代码中的注释“不要更改下面的任何内容”。可能的解决方案是什么?
此解决方案仅适用于 two
使用不同数据的连续调用,因此我正在努力扩展它,但现在,我希望能让您对如何实施它有一个很好的了解
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;
}
您可以使用由 ID 键控的 queues 的散列 table,这样只有具有相同 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);
}
我参加了 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
请注意代码中的注释“不要更改下面的任何内容”。可能的解决方案是什么?
此解决方案仅适用于 two
使用不同数据的连续调用,因此我正在努力扩展它,但现在,我希望能让您对如何实施它有一个很好的了解
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;
}
您可以使用由 ID 键控的 queues 的散列 table,这样只有具有相同 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);
}