如何限制flatMap的并发性?

时间:2014-09-30 00:44:22

标签: javascript rxjs

我正在尝试使用RxJS编写一个脚本来处理数百个日志文件,每个文件大约1GB。脚本的骨架看起来像

Rx.Observable.from(arrayOfLogFilePath)
.flatMap(function(logFilePath){
   return Rx.Node.fromReadStream(logFilePath)
   .filter(filterLogLine)
})
.groupBy(someGroupingFunc)
.map(someFurtherProcessing)
.subscribe(...)

代码有效,但请注意所有日志文件的过滤步骤将同时启动。但是,从文件系统IO性能的角度来看,最好一个接一个地处理一个文件(或者至少将并发限制为几个文件而不是同时打开所有数百个文件)。在这方面,我如何以“功能反应方式”实施?

我曾想过调度程序,但无法弄清楚它是如何帮助的。

2 个答案:

答案 0 :(得分:13)

您可以使用.merge(maxConcurrent)来限制并发性。因为.merge(maxConcurrent)将metaobservable(可观察的可观察对象)展平为可观察对象,所以需要将.flatMap替换为.map,以便输出是metaobservable(“unflat”),然后调用.merge(maxConcurrent)

Rx.Observable.from(arrayOfLogFilePath)
.map(function(logFilePath){
   return Rx.Node.fromReadStream(logFilePath)
   .filter(filterLogLine)
})
.merge(2) // 2 concurrent 
.groupBy(someGroupingFunc)
.map(someFurtherProcessing)
.subscribe(...)

此代码尚未经过测试(因为我无法访问您拥有的开发环境),但这是如何继续进行的。 RxJS没有很多具有并发参数的运算符,但您几乎总能通过.merge(maxConcurrent)执行所需的操作。

答案 1 :(得分:1)

我刚刚用RxJs 5解决了类似的问题,所以我希望解决方案可以帮助其他人解决类似的问题。

// Simulate always processing 2 requests in parallel (when one is finished it starts processing one more),
// retry two times, push error on stream if retry fails.

//const Rx = require('rxjs-es6/Rx');

// -- Global variabel just to show that it works. --
let parallelRequests = 0;
// --------------------------------------------------

function simulateRequest(req) {
    console.log("Request " + req);
    // --- To log retries ---
    var retry = 0;
    // ----------------------

    // Can't retry a promise, need to restart before the promise is made.
    return Rx.Observable.of(req).flatMap(req => new Promise((resolve, reject) => {

        var random = Math.floor(Math.random() * 2000);
        // -- To show that it works --
        if (retry) {
            console.log("Retrying request " + req + " ,retry " + retry);
        } else {

            parallelRequests++;
        }
        // ---------------------------
        setTimeout(() => {
            if (random < 900) {
                retry++;
                return reject(req + " !!!FAILED!!!");
            }

            return resolve(req);
        }, random);
    })).retry(2).catch(e => Rx.Observable.of(e));
}

Rx.Observable.range(1, 10)
    .flatMap(e => simulateRequest(e), null, 2)
    // -- To show that it works --
    .do(() => {
        console.log("ParallelRequests " + parallelRequests);
        parallelRequests--;
    })
    // ---------------------------
    .subscribe(e => console.log("Response from request " + e), e => console.log("Should not happen, error: " + e), e => console.log("Finished"));
<script src="https://npmcdn.com/@reactivex/rxjs@5.0.0-beta.6/dist/global/Rx.umd.js"></script>