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

Posted

技术标签:

【中文标题】在 Node JS 中从不同的“会话”读取/写入相同的文件内容是不是有风险?【英文标题】:Is there any risk to read/write the same file content from different 'sessions' in Node JS?在 Node JS 中从不同的“会话”读取/写入相同的文件内容是否有风险? 【发布时间】:2016-04-30 08:31:39 【问题描述】:

我是Node JS 的新手,我想知道下面提到的sn-ps 代码是否有多会话 问题。

考虑一下我有 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 列表,我更新(计数器+1)来自从文件加载的对象emailsFromFile 的这些电子邮件。

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

任何人都可以传播这个问题吗?

【问题讨论】:

【参考方案1】:

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

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

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

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

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

【讨论】:

问题是:当一个“会话”加载电子邮件计数器时,假设3,并运行+1,在它存储回来之前,其他会话已经更新了这个计数器,所以它实际上应该是5,但第一个会话存储 4 个而不是 @MaximShoustin - 请再次阅读我的回答。 doJob() 正在运行时,不能运行其他请求。所以当doJob() 运行时,没有其他东西可以改变会话。这是因为doJob() 是完全同步的代码。如果它是异步的,那就另当别论了。

以上是关于在 Node JS 中从不同的“会话”读取/写入相同的文件内容是不是有风险?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Node.js 中从不同的应用程序注入模块

mysql写入后立即读取数据?

Hibernate将对象保存到多个会话

在 Node.js 中创建一个持久的 bash shell 会话,知道命令何时完成,并读取和修改源/导出的变量

node.js同步及异步读取写入删除文件1

如何使用 Node.js 读取/写入图像?