Javascript node.js异步迭代时的数据一致性
我有一个工具,其基本思想如下:Javascript node.js异步迭代时的数据一致性,javascript,node.js,asynchronous,concurrency,couchdb,Javascript,Node.js,Asynchronous,Concurrency,Couchdb,我有一个工具,其基本思想如下: //get a bunch of couchdb databases. this is an array const jsonFile = require('jsonfile'); let dbList = getDbList(); const filePath = 'some/path/to/file'; const changesObject = {}; //iterate the db list. do asyn
//get a bunch of couchdb databases. this is an array
const jsonFile = require('jsonfile');
let dbList = getDbList();
const filePath = 'some/path/to/file';
const changesObject = {};
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db){
let merchantDb = nano.use(db);
//get some changes from the database. validate inside callback
merchantDb.get("_changes", function(err,changes){
validateChanges(changes);
changesObject['db'] = changes.someAttribute;
//write changes to file
jsonFile.writeFile(filePath, changesObject, function (err) {
if (err) {
logger.error("Unable to write to file: ");
}
});
})
const validateChanges = function(changes) {
if (!validateLogic(changes) sendAlertMail();
}
为了提高性能,迭代不是同步完成的。因此,可以“并行”运行多个迭代。我的问题是,这会导致数据不一致和/或文件写入过程中出现任何问题吗
编辑:
每次迭代都会写入相同的文件
编辑:2
这些更改存储为带有键值对的JSON对象。关键是数据库名。如果您真的要写入一个文件,而您看起来是这样的(尽管很难确定),那么就不要;您有一个竞争条件,在此条件下,多个回调将尝试写入同一个文件,可能同时写入(请记住,除非您使用
*Sync
函数,否则不会在节点中的JavaScript线程上执行I/O操作),这充其量意味着最后一个回调获胜,最坏情况下意味着由于重叠而出现I/O错误
如果要为每个db
写入单独的文件,那么只要validateChanges
、validateLogic
、sendAlertMail
等之间没有串扰(共享状态),就可以了
只是为了细节:它将启动任务(作业),获取更改,然后将其写出来;调用get
的回调要等到所有作业排队后才能运行
您正在循环中创建闭包,但是您这样做是可以的,这既因为您在forEach
回调中进行闭包,也因为您在get
回调中没有使用db
(这对于forEach
回调很好,但是对于其他一些可能循环数组的方式则不行)。如果您感兴趣,请参阅中有关这方面的详细信息
不过,这条线值得怀疑:
let merchantDb = nano.use('db');
我猜你的意思是(没有引用):
值得一提的是,从问题的更新和您的各种评论中可以看出,更好的解决方案是而不是每次单独写出文件。相反,您希望收集更改,然后将其写出来 您可以像这样使用经典的节点回调API:
let completed = 0;
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db) {
let merchantDb = nano.use(db);
//get some changes from the database. validate inside callback
merchantDb.get("_changes", function(err, changes) {
if (err) {
// Deal with the fact there was an error (don't return)
} else {
validateChanges(changes);
changesObject[db] = changes.someAttribute; // <=== NOTE: This line had 'db' rather than db, I assume that was meant to be just db
}
if (++completed === dbList.length) {
// All done, write changes to file
jsonFile.writeFile(filePath, changesObject, function(err) {
if (err) {
logger.error("Unable to write to file: ");
}
});
}
})
});
let completed=0;
//迭代数据库列表。在每次迭代中执行异步操作
forEach(函数(db){
设Tdb=nano.use(db);
//从数据库中获取一些更改。验证内部回调
merchantDb.get(“\u changes”),函数(err,changes){
如果(错误){
//处理发生错误的事实(不返回)
}否则{
验证变更(变更);
changesbject[db]=changes.someAttribute;//回答这个问题需要太多的猜测(我在开始回答后意识到)。什么是jsonFile
?什么是file
?你的真正意思是nano.use('db')
,而不是nano.use(db)
?感谢您的回复。是的,它应该是nano.use(db)
。为了更好的可读性,我添加了一些导入语句。每次迭代都会写入同一个文件。@fsociety:那么不,它一点也不安全。您在单个文件上安排多个I/O操作,这可能会重叠(请记住,除非您使用*Sync
函数,否则不会在节点中的JavaScript线程上执行I/O操作),即使它们没有重叠,也将是“最后一个赢”,因为您没有指定附加选项。从writeFile
(其中jsonfile.writeFile
包装):异步将数据写入文件,如果文件已经存在,则替换该文件。"每次迭代都会实现一个附加。我修改了这个问题以反映这一点。您对如何处理此处的文件写入有什么建议吗?像maybe这样的简单队列实现?@fsociety:不,知道何时完成多个异步操作并不需要使它们同步。是的,这将涉及回调函数。我不明白为什么会有问题,因为当前代码使用回调函数。事实上,有三个::-)如果您有时间限制,我肯定会避免不必要的I/O。我已经更新了答案,以显示您在这种情况下如何做到这一点。@fsocity:JavaScript语言不一定是单线程的。但是Node只运行一个JavaScript线程,所以我们不必担心上面提到的并发性,不。
let completed = 0;
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db) {
let merchantDb = nano.use(db);
//get some changes from the database. validate inside callback
merchantDb.get("_changes", function(err, changes) {
if (err) {
// Deal with the fact there was an error (don't return)
} else {
validateChanges(changes);
changesObject[db] = changes.someAttribute; // <=== NOTE: This line had 'db' rather than db, I assume that was meant to be just db
}
if (++completed === dbList.length) {
// All done, write changes to file
jsonFile.writeFile(filePath, changesObject, function(err) {
if (err) {
logger.error("Unable to write to file: ");
}
});
}
})
});