【问题标题】:NodeJS: Reading and writing to a shared object from multiple promisesNodeJS:从多个承诺读取和写入共享对象
【发布时间】:2020-12-21 15:49:51
【问题描述】:

我试图找出从多个 Promise 访问对象时是否存在问题,例如:

let obj = {test: 0}
let promisesArr = []

for (let n = 0; n < 10; n++) {
    promisesArr.push(promiseFunc(obj))
}

Promise.all(promisesArr)

// Then the promise would be something like this 
function promiseFunc(obj) {
    return new Promise(async (resolve, reject) => {
        // read from the shared object
        let read = obj.test
        // write/modify the shared object
        obj.test++
        // Do some async op with the read data
        await asyncFunc(read)
        // resolves and gets called again later
    })
}

从我所看到/测试的情况来看,不会有问题,即使处理是异步的,似乎也没有竞争条件。但也许我可能会遗漏一些东西。

我能看到的唯一问题是写入对象,然后执行一些 I/O 操作,然后读取预期之前写入的内容仍然存在

我只是在开始时才在其他异步操作之后修改对象,但是有几个 Promise 做同样的事情。一旦他们解决了,他们就会再次被调用并重新开始循环。

【问题讨论】:

  • JS 是单线程的。如果您不使用工人,您不必担心。

标签: node.js concurrency promise es6-promise


【解决方案1】:

具有多个异步操作的 Javascript 中的竞争条件完全取决于您正在执行的应用程序逻辑。

由于您没有在这方面显示任何真实代码,因此我们无法确定您是否有竞争条件责任。

您的问题没有通用答案。

是的,访问相同数据的多个异步操作之间可能存在竞争条件。

可以适当地编写代码,以免发生竞争条件。

这一切都取决于准确和真实的代码以及它在做什么。没有通用的答案。我可以向您展示带有两个绝对会导致竞争条件的基于 promise 的异步操作的代码,并且我可以向您展示带有两个不会导致竞争条件的基于 promise 的异步操作的代码。 因此,对竞态条件的敏感性取决于精确的代码、它在做什么以及它是如何编写的。

对共享对象中值的纯粹和简单访问本身不会导致竞争条件,因为 Javascript 中的主线程是单线程且不可中断的,因此任何单个同步 Javascript 语句本身都是线程安全的。重要的是您如何处理这些数据以及如何编写代码。


如果有其他操作也可以更改shareObj.someProperty,这是一个容易受到竞争条件影响的示例:

let localValue = shareObj.someProperty;
let data = await doSomeAsyncOperation();
shareObj.someProperty = localValue + data.someProperty;

然而,这不会导致竞争条件:

let data = await doSomeAsyncOperation();
shareObj.someProperty = shareObj.someProperty += data.someProperty;

第二个不会导致它自己的竞争条件,因为它会自动更新共享数据。而第一个是获取它,将其存储在本地,然后等待异步操作完成,这是其他代码在本地函数不知道的情况下修改共享变量的机会。

仅供参考,这与经典数据库问题非常相似。如果您从数据库中获取一个值(这在 nodejs 中始终是一个异步操作),然后递增它,然后将值写回,这会受到竞争条件的影响,因为其他人可能会同时尝试读取/修改该值并且你可以踩对方的变化。因此,您必须使用内置在数据库中的原子操作来在一个原子操作中更新变量。

对于您自己的 Javascript 变量,问题比通用数据库问题要简单一些,因为读取和写入 Javascript 变量是原子的。您只需确保不会保留稍后将在异步操作中修改和写回的值。

【讨论】:

  • 好的,我明白你的意思,我想你已经回答了我的问题。我已经编辑了代码以更好地显示正在发生的事情。我想知道的是您指出的,当您出去执行异步操作时,另一个函数有可能编辑您的对象。你应该关心在异步操作之后是否需要返回这些数据,对吧?
  • @FranciscoRangel - 是的,nodejs 本质上是协作式多任务,而不是抢先式多任务。在您等待异步操作完成时,其他代码可以运行并且可以在您等待时更改任何共享状态/对象。您必须在设计中预见到这一点,以及如何编写完全特定于应用程序的代码。如果这回答了您的问题,您可以通过单击左侧的复选标记向社区表明这一点。
猜你喜欢
  • 2018-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-25
  • 2017-02-25
  • 1970-01-01
相关资源
最近更新 更多