javascript - 如何确保两个客户端不会同时请求破坏状态

标签 javascript node.js express concurrency

我是 Node JS 新手,正在构建一个依赖文件系统的小型应用程序。

假设我的应用程序的目标是填充如下文件:

1
2
3
4
..

我希望在每次请求时,都会以正确的顺序将新行写入文件。

我能实现这个目标吗?

我知道我不能在不编写任何代码的情况下提出我的问题,所以就在这里。我正在使用 Express JS 服务器:

(我们假设该文件在第一次代码启动时仅包含 1)

import express from 'express'
import fs from 'fs'

let app = express();

app.all('*', function (req, res, next) {
    // At every request, I want to write my file
    writeFile()
    next()
})

app.get('/', function(req,res) {
    res.send('Hello World')
})

app.listen(3000, function (req,res) {
    console.log('listening on port 3000')
})

function writeFile() {
    // I get the file
    let content = fs.readFileSync('myfile.txt','utf-8')

    // I get an array of the numbers
    let numbers = content.split('\n').map(item => {
        return parseInt(item)
    })

    // I compute the new number and push it to the list
    let new_number = numbers[numbers.length - 1] + 1
    numbers.push(new_number)

    // I write back the file
    fs.writeFileSync('myfile.txt',numbers.join('\n'))
}

我试图猜测同步过程,这让我认为我确信在同一时刻没有发生任何其他事情,但我真的很确定......

如有不清楚的地方,请在评论中告诉我

最佳答案

如果我没理解错的话,你害怕的是race condition在这种情况下,如果两个客户端同时到达 HTTP 服务器,则文件将以相同的内容保存,其中数字仅增加一次而不是两次。

解决这个问题的简单方法是确保共享资源一次只能访问或修改一次。在这种情况下,使用同步方法可以解决您的问题。因为当它们执行时,整个 Node 进程被阻塞,不会执行任何操作。

如果您在没有任何其他并发控制措施的情况下更改同步方法及其异步对应部分,那么您的代码肯定容易受到竞争条件或损坏状态的影响。

现在,如果这只是您的应用程序正在做的事情,那么最好保持这种方式,因为它非常简单,但是假设您想向其中添加其他功能,在这种情况下您可能希望避免任何同步方法因为它会阻止进程并且不会让您有任何并发​​性。

添加并发控制的一个简单方法是使用一个计数器来跟踪排队的请求数量。如果没有任何东西排队(counter === 0),那么我们只读取和写入文件,否则我们添加到计数器。一旦写入文件完成,我们就减少计数器并重复:

app.all('*', function (req, res, next) {
  // At every request, I want to write my file
  writeFile();
  next();
});

let counter = 0;

function writeFile() {
  if (counter === 0) {
    work(function onWriteFileDone() {
      counter--;
      if (counter > 0) {
        work();
      }
    });
  } else {
    counter++;
  }

  function work(callback) {
    // I get the file
    let content = fs.readFile('myfile.txt','utf-8', function (err, content) { 
      // ignore the error because life is too short on stackoverflow questions...

      // I get an array of the numbers
      let numbers = content.split('\n').map(parseInt);

      // I compute the new number and push it to the list
      let new_number = numbers[numbers.length - 1] + 1;
      numbers.push(new_number);

      // I write back the file
      fs.writeFile('myfile.txt',numbers.join('\n'), callback);
    });
  }
}

当然这个函数没有任何参数,但是如果你想向它添加任何参数,你必须使用队列而不是在队列中存储参数的计数器。

现在不要编写自己的并发机制。 Node 生态系统中有很多。例如,您可以使用 async module, which provide a queue .

请注意,如果一次只有一个进程,那么您不必担心多个线程,因为在 Node.js 中,在一个进程中一次只有一个执行线程,但假设有多个线程然后处理写入文件,这可能会使事情变得更加复杂,但如果还没有涉及的话,让我们将其保留到另一个问题。操作系统提供了几种不同的方法来处理此问题,您也可以使用自己的锁定文件或专用进程来写入文件或消息队列进程。

关于javascript - 如何确保两个客户端不会同时请求破坏状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41560131/

相关文章:

javascript - 在 Gulp/BrowserSync 中启用 Cors

javascript - 使用ajax实时更新javascript变量

node.js - 将没有端口号的域名链接到 nginx 托管的 MEAN stack 服务器

node.js - 间歇性 502 错误网关错误(使用 nginx、nodejs、mongodb)

node.js - 使用 Passport 对 Facebook 进行身份验证不起作用

javascript - 哟发电机子发电机不可用。当进行 NPM 安装时,它不会拉取所有代码

javascript - 从 HashTable 存储和检索 KO ObservableArray

node.js - 文件上传期间写入文件流 - node.js 和 node-formidable

node.js - ExpressJS 多域 https 托管

node.js - 从路由器传递值到 Node js中查看