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

时间:2016-01-23 20:55:46

标签: node.js express fs

我是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);            
    };
 }

因此,doJob方法会收到_emails个列表,并且会从文件加载的对象emailsFromFile更新(计数器+1)这些电子邮件。

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

有人可以就这个问题传播一下吗?

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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