变量上的JavaScript事件循环操作是否阻塞?
在JavaScript的非阻塞事件循环中,读取并更改变量是否安全?如果两个进程几乎同时更改一个变量,会发生什么情况 示例A:变量上的JavaScript事件循环操作是否阻塞?,javascript,node.js,asynchronous,concurrency,event-loop,Javascript,Node.js,Asynchronous,Concurrency,Event Loop,在JavaScript的非阻塞事件循环中,读取并更改变量是否安全?如果两个进程几乎同时更改一个变量,会发生什么情况 示例A: 过程1:获取变量A(它是100) 过程2:获取变量A(它是100) 流程1:添加1(它是101) 流程2:添加1(它是101) 结果:变量A是101而不是102 这是一个简化的例子,有一条快速路线。假设路由每秒调用1000次: let counter = 0; const getCounter = () => { return counter; }; c
- 过程1:获取变量A(它是100)
- 过程2:获取变量A(它是100)
- 流程1:添加1(它是101)
- 流程2:添加1(它是101)
- 结果:变量A是101而不是102
let counter = 0;
const getCounter = () => {
return counter;
};
const setCounter = (newValue) => {
counter = newValue;
};
app.get('/counter', (req, res) => {
const currentValue = getCounter();
const newValue = currentValue + 1;
setCounter(newValue);
});
示例B:
如果我们做一些更复杂的事情,比如Array.findIndex()
,然后Array.splice()
?可能是因为另一个事件进程已经更改了数组,所以找到的索引已经过时了吗
- 处理findIndex(它是12000)
- 过程B findIndex(它是34000)
- 处理拼接索引12000
- 过程B拼接索引34000
- 结果:进程B删除了错误的索引,应改为删除了33999
const veryLargeArray = [
// ...
];
app.get('/remove', (req, res) => {
const id = req.query.id;
const i = veryLargeArray.findIndex(val => val.id === id);
someAsyncFunction().then(() => {
veryLargeArray.splice(i, 1);
});
});
这个问题很难找到合适的词语来描述。请随时更新标题。根据@ThisIsNoZaku的链接,Javascript有一个“从运行到完成”的原则: 在处理任何其他消息之前,每个消息都会被完全处理 在对程序进行推理时,这提供了一些很好的属性,包括这样一个事实:每当函数运行时,它都不能被抢占,并且将在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。这与C不同,例如,如果一个函数在一个线程中运行,运行时系统可能会在任何时候停止该函数,以便在另一个线程中运行其他代码 这种模式的一个缺点是,如果消息需要太长时间才能完成,web应用程序将无法处理诸如单击或滚动之类的用户交互。浏览器通过“脚本运行时间过长”对话框缓解此问题。要遵循的一个良好实践是缩短消息处理时间,如果可能,将一条消息缩减为多条消息 进一步阅读: 因此,对于: 示例A:作为sitecounter,它可以很好地工作 示例B:这也很好,但是如果许多请求同时发生,那么最后提交的请求将等待相当长的一段时间 示例C:如果在
someAsyncFunction
完成之前发送了对\remove
的另一个调用,则完全可能是数组无效。解决这个问题的方法是将索引查找移动到异步函数的.then
子句中
在IMO中,以延迟为代价,这解决了许多潜在的痛苦并发问题。如果您必须优化请求的速度,那么我的建议是研究不同的体系结构(附加缓存等)。像
Array.findIndex()
或Array.map()
不是异步的,它们是同步的,但是app.get()
是吗?您给出的示例都是使用内存数据的全局变量。你不应该在任何地方这样做。甚至不建议这样做。@xdeepakv这只是一个抽象问题的示例。本文档概述了Javascript并发模型:如果是这样,示例C不应该工作,是吗?我的错,是的,不能保证示例C可以工作。
const veryLargeArray = [
// ...
];
app.get('/remove', (req, res) => {
const id = req.query.id;
const i = veryLargeArray.findIndex(val => val.id === id);
someAsyncFunction().then(() => {
veryLargeArray.splice(i, 1);
});
});