我需要处理100万行记录,转换它们中的每一行,然后将它们保存到多个文件中(按小时分箱;每小时1个文件 - 我想用“过滤器”拆分它们)
出于某种原因,我需要严格按顺序处理这些行。意思是,如果第#450000行需要更长的时间来处理和保存(这是棘手的部分,因为fs与回调异步),处理不会跳转到#450001 ...它将等到450000完成。在代码中随机休眠就是模拟那种情况。
以前(使用简单的Promise,没有RxJ),我会创建N个promise,每行一个,将它们保存在一个数组中,然后通过reduce op进行链接,如下所述:https://github.com/kriskowal/q
但我不想创建100万个Promise实例。所以,我调查了ReactiveX,希望它会像“推卸责任”;意味着它不会等待,一旦事件弹出就会发生处理,并且处理所使用的资源(认为处理块基本上是场景背后的承诺)将尽快释放。
我尝试使用此代码验证:
import Rx from 'rxjs-es6/Rx';
import Q from 'q';
let subject = new Rx.Subject();
let processEventJsons = function(observable) {
observable.concatMap(eventJson => {
let deferred = Q.defer();
setTimeout(() => {
eventJson.procDatetime = new Date().toISOString();
deferred.resolve(eventJson);
}, Math.random() * 5000);
return Rx.Observable.fromPromise(deferred.promise)
})
.subscribe({
next: enrichedEventJson => {
console.log(JSON.stringify(enrichedEventJson));
},
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done'),
});
}
processEventJsons(
subject.filter(dataJson => dataJson.type === "interview").map(dataJson => {
return {event: "intv", datetime: dataJson.datetime}
})
)
processEventJsons(
subject.filter(dataJson => dataJson.type === "checkin").map(dataJson => {
return {event: "chki", datetime: dataJson.datetime}
})
)
for (let i = 0; i < 1000000; i++) {
if (Math.random() < 0.5) {
subject.next({id: i, type: "interview", datetime: new Date().toISOString()});
} else {
subject.next({id: i, type: "checkin", datetime: new Date().toISOString()});
}
}
subject.complete();
但是......我一直在接受:
致命错误:CALL_AND_RETRY_LAST分配失败 - JavaScript堆内存不足。
console.log(JSON.stringify(enrichedEventJson));直到“for-loop”(代码末尾)完成后才会打印。
这让我觉得转换到RxJS并没有真正改善这种情况;它仍然在现场排队等待承诺。
或者我错误地使用了API?你能帮我指出什么是错的吗?
假旗。弄清楚问题不在于使用RxJS,而是在for-loop中(它太紧了)。所以我改为:
for (let i = 0; i < 1000000; i++) {
if (Math.random() < 0.5) {
setTimeout(() => {
subject.next({id: i, type: "interview", datetime: new Date().toISOString()});
});
} else {
setTimeout(() => {
subject.next({id: i, type: "checkin", datetime: new Date().toISOString()});
});
}
}
答案 0 :(得分:2)
我会创建N个promise,每行一个,将它们保存在一个数组中,然后通过reduce op进行链接
这是一种简单但需要内存的方法。它使用了需要同时存在的一百万个承诺。相反,您可以使用递归方法在常量内存中按顺序处理行:
function getInput(i) {
return {id: i, type: Math.random() < 0.5 ? "interview" : "checkin", datetime: new Date().toISOString()};
}
function process(eventJson) {
let deferred = Q.defer();
setTimeout(() => {
eventJson.procDatetime = new Date().toISOString();
deferred.resolve(eventJson);
}, Math.random() * 5000);
return deferred.promise;
}
function filteredProcess({type, datetime}) {
if (type === "interview")
return process({event: "intv", datetime});
if (type === "checkin")
return process({event: "chki", datetime});
}
function log(enrichedEventJson) {
console.log(JSON.stringify(enrichedEventJson));
}
function loop(i) {
if (i < 1000000)
return getInput(i)
.then(filteredProcess)
.then(log)
.then(() => loop(i+1));
else
return Q("done")
}
loop().then(console.log, err => console.error('something wrong occurred: ' + err));