我是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
时,第二个请求可能会更改文件内容。
有人可以就这个问题传播一下吗?
答案 0 :(得分:3)
因为doJob()
函数中的代码都是同步的,所以不存在多个请求导致并发问题的风险。
如果您在该函数中使用异步IO,那么可能会出现并发问题。
要解释一下,node.js中的Javascript是单线程的。因此,一次只运行一个Javascript执行线程,并且该执行线程一直运行,直到它返回到事件循环。因此,doJob()
中的任何完全同步代码序列都将在不中断的情况下完成。
另一方面,如果您使用fs.readFile()
而不是fs.readFileSync()
之类的任何异步操作,那么该执行线程将在您调用{{1}时返回到事件循环并且在读取文件时可以运行另一个请求。如果是这种情况,那么最终可能会有两个请求在同一个文件上发生冲突。在这种情况下,您必须实现某种形式的并发保护(某种标志或队列)。这是数据库为其提供许多功能的类型。
我有一个在Raspberry Pi上运行的node.js应用程序,该应用程序使用大量异步文件I / O,并且我可能会与来自多个请求的代码发生冲突。我通过在写入特定文件的任何时候设置标志来解决它,并且任何其他想要写入该文件的请求首先检查该标志,如果设置了,那么进入我自己队列的那些请求随后会被提供。请求完成其写入操作。还有很多其他方法可以解决这个问题。如果在很多地方发生这种情况,那么获得一个为这种类型的写争用提供功能的数据库可能是值得的。