英文:
Increment counter sequentially in Node.js
问题
我想知道如何确保在Node.js环境中正确递增计数器。
如果我理解正确,异步函数是由4个libuv库线程实例化的非主线程处理的,回调函数由主线程(事件循环)执行。
如果上面的说法正确,那么下面的代码可能会导致计数器的不正确更新,因为f1()
和f2()
可能同时尝试更新counter
,最终结果为1
而不是2
。
我如何重写以下代码以确保正确更新计数器?
var counter = 0
async function f1() {
// 做一些操作
counter++
}
async function f2() {
// 做一些操作
counter++
}
f1()
f2()
英文:
I want to know how can I ensure that I increment counter correctly in Node.js environment.
If I understand correctly, async functions are processed by non-main threads that are instantiated by 4 libuv library threads, and the callbacks are executed by the main thread (event loop).
If above is true, then below code can result in incorrect updates to counter because f1()
& f2()
can try to update counter
at the same time giving a final result of 1
instead of 2
.
How do I rewrite the code below to ensure correct update to counter?
var counter = 0
async function f1() {
// do something
counter++
}
async function f2() {
// do something
counter++
}
f1()
f2()
答案1
得分: 2
没有,f1
和 f2
没有办法同时访问相同的 counter
变量,因此“最终”结果将是2。但是哪个函数是 f1
或 f2
设置为 1
或 2
是不确定的。
异步函数仍然由唯一的 JavaScript 处理运行,而不是由后台线程运行。也许它们自己会等待一些由其他进程处理的任务,这取决于它们将进行的 API 调用,但是 JavaScript 部分仍然由唯一的 JavaScript 处理运行,可以访问 counter
变量。
因此,在这里没有冲突的风险。
唯一可能出现此类问题的情况是在不同的 JavaScript 上下文之间共享 SharedArrayBuffer
对象时(例如,使用 web workers)。但是对于这种情况,我们有 Atomics
。但是在这里,counter
变量不是 SharedArrayBuffer
,不能在不同上下文之间共享。因此,再次强调,当 f1
和 f2
都以不确定的顺序解决时,counter
将保持值为 2
。
英文:
No, there is no way that f1
and f2
do access the same counter
variable at the same time, so the "final" result will be 2.
However which of f1
or f2
would have set it to 1
or 2
is unsure.
Async functions are still ran by the one and only JS processing, not by background threads. Maybe they will themselves be waiting for some tasks that are processed by other processes, depending on the API calls they'll make, but the JS part is still ran by the one and only JS processing that has access to the counter
variable.
So there is no risk of clashing here.
The only case where you could have such an issue is with SharedArrayBuffer
objects, when shared across different JS contexts (e.g with web workers). Though for this case we have Atomics
.
But here the counter
variable is not a SharedArrayBuffer
, and can't be shared across contexts. So once again, when f1
and f2
will both have resolved in an undetermined order, counter
will hold the value 2
.
答案2
得分: 0
如果我理解正确,异步函数是由非主线程处理的。
这是不正确的。所有异步函数都在主线程中处理。因此,调用 f1()
和 f2()
将始终导致计数器增加两次。它永远不会失败。这是因为 JavaScript 是单线程的。
重要的是要知道 JavaScript 是单线程的。即使是在 Node.js 中由多个线程执行的操作,例如调用 Web Workers 或执行文件 I/O,也会通过事件循环串行化回到主线程。
除非您使用非标准的第三方线程库,否则在 Node.js 中变量访问永远不会同时发生。这是因为在 Node.js 中无法在工作线程之间共享变量(也就是说,如果您使用 worker_threads - 在正常编码中,您甚至不会在单独的线程中执行自己的代码)。数据通过消息在线程之间交换 - 类似于互联网上的客户端和服务器共享数据的方式:它们永远不会访问彼此的变量。
英文:
> If I understand correctly, async functions are processed by non-main threads
This is not true. All async functions are processed in the main thread. Therefore calling f1()
and f2()
will always result in counter being incremented twice. It will never fail. This is because javascript is single threaded.
It is important to know that javascript is single threaded. Even operations that are performed in multiple threads by Node.js such as calling web workers or performing file I/O are serialized back to the main thread by the event loop.
Unless you're using non-standard 3rd party threading libraries variable access in node.js are never simultaneous. This is because variables cannot be shared between workers in node.js (that is, if you use worker_threads - in normal coding you're not even executing your own code in separate threads). Data is exchanged between threads via messages - similar to the way client and servers on the internet share data with each other: they never access each other's variables.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论