在 Node JS 中 read/write 来自不同 'sessions' 的相同文件内容是否有任何风险?
Is there any risk to read/write the same file content from different 'sessions' in Node JS?
我是 Node JS
的新手,我想知道下面提到的代码片段是否有 multisession 问题。
假设我有 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
时,第二个请求 可能会更改文件内容。
任何人都可以解决这个问题吗?
因为doJob()
函数中的代码都是同步的,所以不存在多次请求导致并发问题的风险。
如果您在该函数中使用异步 IO,则可能会出现并发问题。
解释一下,node.js中的Javascript是单线程的。因此,一次只有一个 Javascript 执行线程 运行ning,并且该线程执行 运行s 直到它 returns 返回事件循环。因此,任何像您在 doJob()
中的完全同步的代码序列都将 运行 不间断地完成。
另一方面,如果您使用任何异步操作,例如 fs.readFile()
而不是 fs.readFileSync()
,则该执行线程将 return 返回事件循环点你调用 fs.readFileSync()
并且在读取文件时另一个请求可以是 运行 。如果是这种情况,那么您最终可能会遇到针对同一文件的两个请求发生冲突。在那种情况下,您将不得不实施某种形式的并发保护(某种标志或队列)。数据库为此提供了很多功能。
我在 Raspberry Pi 上有一个 node.js 应用程序 运行ning,它使用大量异步文件 I/O,我可能会与来自多个请求的代码发生冲突。我通过在写入特定文件的任何时候设置一个标志来解决它,并且任何其他想要写入该文件的请求首先检查该标志,如果设置了它,那么进入我自己的队列的那些请求将在之前的时候得到服务请求完成其写操作。还有很多其他方法可以解决这个问题。如果这种情况发生在很多地方,那么获得一个提供此类写争用功能的数据库可能是值得的。
我是 Node JS
的新手,我想知道下面提到的代码片段是否有 multisession 问题。
假设我有 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
时,第二个请求 可能会更改文件内容。
任何人都可以解决这个问题吗?
因为doJob()
函数中的代码都是同步的,所以不存在多次请求导致并发问题的风险。
如果您在该函数中使用异步 IO,则可能会出现并发问题。
解释一下,node.js中的Javascript是单线程的。因此,一次只有一个 Javascript 执行线程 运行ning,并且该线程执行 运行s 直到它 returns 返回事件循环。因此,任何像您在 doJob()
中的完全同步的代码序列都将 运行 不间断地完成。
另一方面,如果您使用任何异步操作,例如 fs.readFile()
而不是 fs.readFileSync()
,则该执行线程将 return 返回事件循环点你调用 fs.readFileSync()
并且在读取文件时另一个请求可以是 运行 。如果是这种情况,那么您最终可能会遇到针对同一文件的两个请求发生冲突。在那种情况下,您将不得不实施某种形式的并发保护(某种标志或队列)。数据库为此提供了很多功能。
我在 Raspberry Pi 上有一个 node.js 应用程序 运行ning,它使用大量异步文件 I/O,我可能会与来自多个请求的代码发生冲突。我通过在写入特定文件的任何时候设置一个标志来解决它,并且任何其他想要写入该文件的请求首先检查该标志,如果设置了它,那么进入我自己的队列的那些请求将在之前的时候得到服务请求完成其写操作。还有很多其他方法可以解决这个问题。如果这种情况发生在很多地方,那么获得一个提供此类写争用功能的数据库可能是值得的。