在Reactor中并行调度`groupBy`组

时间:2015-07-02 12:47:55

标签: java event-driven reactor project-reactor

我正在学习Reactor,我想知道如何实现某种行为。 让我们说我有一串传入的消息。 每条消息都与某个实体相关联,并包含一些数据。

interface Message {
    String getEntityId();
    Data getData();
}

可以并行处理与不同实体相关的消息。 但是,必须一次处理一个与任何单个实体有关的消息,即实体"abc"的消息2的处理在实体"abc"的消息1的处理完成之前不能开始。 在处理消息时,应该缓冲该节点的进一步消息。 其他实体的消息可以不受阻碍地进行。 人们可以将其视为每个实体运行代码的线程如下:

public void run() {
    for (;;) {
        // Blocks until there's a message available
        Message msg = messageQueue.nextMessageFor(this.entityId);

        // Blocks until processing is finished
        processMessage(msg);
    }
}

如何在没有阻止的情况下使用React实现这一目标? 总消息速率可能很高,但每个实体的消息速率将非常低。 实体集可能非常大,并且不一定事先知道。

我想它可能看起来像这样,但我不知道。

{
    incomingMessages()
            .groupBy(Message::getEntityId)
            .flatMap(entityStream -> entityStream
                    /* ... */
                    .map(msg -> /* process the message */)))
                    /* ... */
}

public static Stream<Message> incomingMessages() { /* ... */ }

2 个答案:

答案 0 :(得分:2)

使用ProjectReactor,您可以通过以下方式解决问题:

data.frame

我认为类似的解决方案可能在RxJava

答案 1 :(得分:0)

我们在项目中遇到了同样的问题。具有相同ID的实体必须顺序处理,但是具有不同ID的实体可以并行处理。

解决方案非常简单。代替使用flatMap我们开始使用concatMap。来自concatMap的文档:

 * Transform the elements emitted by this {@link Flux} asynchronously into Publishers,
 * then flatten these inner publishers into a single {@link Flux}, sequentially and
 * preserving order using concatenation.

代码示例:

public void receive(Flux<Data> data) {
    data
        .groupBy(Data::getPointID)
        .flatMap(service::process)
        .onErrorContinue(Logging::logError)
        .subscribe();

}

处理方法:

Flux<SomeEntity> process(Flux<Data> dataFlux) {
    return dataFlux
        .doOnNext(Logging::logReceived)
        .concatMap(this::proceedDefinitionsSearch)
        .doOnNext(Logging::logDefSearch)
        .flatMap(this::processData)
        .doOnNext(Logging::logDataProcessed)
        .concatMap(repository::save)
        .doOnNext(Logging::logSavedEntity);
}