我想知道如何确保在Node.js环境中正确地递增计数器。
如果我理解正确的话,异步函数由非主线程处理,这些非主线程由4个libuv库线程示例化,回调由主线程执行(事件循环)。
如果上述为真,则以下代码可能会导致计数器的错误更新,因为f1()
和f2()
可以尝试同时更新counter
,最终结果为1
而不是2
。
如何重写下面的代码以确保计数器的正确更新?
var counter = 0
async function f1() {
// do something
counter++
}
async function f2() {
// do something
counter++
}
f1()
f2()
2条答案
按热度按时间camsedfj1#
不,
f1
和f2
不可能同时访问同一个counter
变量,因此“最终”结果将是2。然而,
f1
或f2
中的哪一个将其设置为1
或2
是不确定的。异步函数仍然由唯一的JS处理运行,而不是后台线程。也许他们自己会等待一些由其他进程处理的任务,这取决于他们将进行的API调用,但JS部分仍然由唯一可以访问
counter
变量的JS处理运行。所以这里没有冲突的风险。
唯一可能出现这种问题的情况是
SharedArrayBuffer
对象,当在不同的JS上下文中共享时(例如web workers)。在这种情况下,我们有Atomics
。但是这里的
counter
变量不是SharedArrayBuffer
,并且不能跨上下文共享。因此,当f1
和f2
都以未确定的顺序解析时,counter
将保持值2
。jckbn6z72#
如果我理解正确的话,异步函数是由非主线程处理的
这不是真的所有的async函数都在主线程中处理。因此,调用
f1()
和f2()
将始终导致计数器递增两次。它永远不会失败。这是因为JavaScript是单线程的。重要的是要知道JavaScript是单线程的。即使是Node.js在多个线程中执行的操作,例如调用Web Worker或执行文件I/O,也会通过事件循环序列化回主线程。
除非你使用非标准的第三方线程库,否则node.js中的变量访问永远不会同时进行。这是因为变量不能在node.js中的worker之间共享(也就是说,如果你使用worker_threads -在正常的编码中,你甚至不会在单独的线程中执行自己的代码)。数据通过消息在线程之间交换-类似于互联网上的客户端和服务器彼此共享数据的方式:它们从不访问彼此的变量。