在 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 中从不同的“会话”读取/写入相同的文件内容是不是有风险?的主要内容,如果未能解决你的问题,请参考以下文章