从 Node JS 中的不同“会话”读取/写入相同的文件内容是否存在风险?

Max*_*tin 3 fs node.js express

我是新来的Node JS,我想知道下面提到的代码片段是否存在多会话问题。

考虑我有 Node JS 服务器 ( express) 并且我监听一些POST请求:

app.post('/sync/:method', onPostRequest);

var onPostRequest = function(req,res){

  // parse request and fetch email list
  var emails = [....]; // pseudocode 

  doJob(emails);

  res.status(200).end('OK');
}

 function doJob(_emails){

    try {
        emailsFromFile = fs.readFileSync(FILE_PATH, "utf8") || {};

        if(_.isString(oldEmails)){
           emailsFromFile = JSON.parse(emailsFromFile); 
        }

         _emails.forEach(function(_email){

            if( !emailsFromFile[_email] ){
               emailsFromFile[_email] = 0;
            }
            else{
               emailsFromFile[_email] += 1;
            }                
        });

        // write object back
        fs.writeFileSync(FILE_PATH, JSON.stringify(emailsFromFile));

    } catch (e) {
         console.error(e);            
    };
 }
Run Code Online (Sandbox Code Playgroud)

因此, doJob方法接收_emails列表,然后我从文件加载的对象更新(计数器+1)这些电子邮件emailsFromFile

考虑一下我同时收到 2 个请求并且它触发了doJob两次。我担心当一个请求emailsFromFile从文件加载时,第二个请求可能会更改文件内容。

有人可以阐明这个问题吗?

jfr*_*d00 5

由于函数中的代码doJob()都是同步的,因此不存在多个请求导致并发问题的风险。

如果您在该函数中使用异步 IO,则可能会出现并发问题。

解释一下,node.js 中的 Javascript 是单线程的。因此,一次只有一个 Javascript 执行线程在运行,并且该执行线程一直运行直到返回到事件循环。因此,任何像您这样的完全同步代码序列都doJob()将不间断地运行完成。

另一方面,如果您使用任何异步操作(例如,fs.readFile()而不是 )fs.readFileSync(),那么执行线程将返回到您调用时的事件循环fs.readFileSync(),并且可以在读取文件时运行另一个请求。如果是这种情况,那么最终可能会导致两个请求在同一文件上发生冲突。在这种情况下,您必须实现某种形式的并发保护(某种标志或队列)。数据库为此提供了大量功能。

我有一个在 Raspberry Pi 上运行的 Node.js 应用程序,该应用程序使用大量异步文件 I/O,并且我可能会与来自多个请求的代码发生冲突。我通过在写入特定文件时设置一个标志来解决这个问题,并且想要写入该文件的任何其他请求首先检查该标志,如果设置了该标志,那么进入我自己的队列的那些请求将在先前的情况下得到服务请求完成其写操作。还有很多其他方法可以解决这个问题。如果这种情况在很多地方发生,那么可能值得购买一个为此类写入争用提供功能的数据库。