Rx java 如何在并行处理的RxJava组中引入延迟?

Rx java 如何在并行处理的RxJava组中引入延迟?,rx-java,reactive-programming,rx-java2,Rx Java,Reactive Programming,Rx Java2,我的用例是将一个流分组,并行地开始处理一些组,在每个组中,以固定的间隔延迟每个项目的处理。我似乎无法在组内获得正确的延迟,因为它们不是周期性地发射,而是几乎瞬间发射。以下是我使用RxJava 2.0.5的测试代码: @Slf4j public class GroupsAndDelays { Function<Integer, Flowable<Integer>> remoteClient; int groupMemberDelaySeconds;

我的用例是将一个流分组,并行地开始处理一些组,在每个组中,以固定的间隔延迟每个项目的处理。我似乎无法在组内获得正确的延迟,因为它们不是周期性地发射,而是几乎瞬间发射。以下是我使用RxJava 2.0.5的测试代码:

@Slf4j
public class GroupsAndDelays {
    Function<Integer, Flowable<Integer>> remoteClient;
    int groupMemberDelaySeconds;
    int remoteCallTimeoutSeconds;
    int maxRetryCount;
    int retryDelaySeconds;
    Map<Long, List<Integer>> threadMap;
    Map<Long, List<Integer>> resultThreadMap;

    public ParallelFlowable<Integer> doStuff(Flowable<Integer> src,
                                             Function<Integer, Integer> groupByFn,
                                             Function<Integer, Flowable<Integer>> responseMapper) {
        return src
                .groupBy(groupByFn)
                .parallel(5).runOn(Schedulers.newThread())
                .map(g -> g.distinct().toList())
                .flatMap(i -> i.toFlowable())
                .flatMap(i -> {
                    log.debug("Processing group: {}.", i);
                    return Flowable.fromIterable(i)
                            .delay(groupMemberDelaySeconds, SECONDS);
                })
                .flatMap(i -> {
                    log.debug("Processing: {}.", i);
                    putInThreadMap(threadMap, i);
                    return remoteCall(i * 2, responseMapper);
                });
    }

    private Flowable<Integer> remoteCall(int i, Function<Integer, Flowable<Integer>> responseMapper) throws
            Exception {
        return remoteClient.apply(i)
                .timeout(remoteCallTimeoutSeconds, SECONDS)
                .retryWhen(t -> t.zipWith(Flowable.range(1, maxRetryCount), (ex, retryCount) -> retryCount)
                        .flatMap(retryCount -> Flowable.timer(retryCount * retryDelaySeconds, SECONDS)))
                .flatMap(result -> {
                    log.debug("Processing result: {}.", result);
                    putInThreadMap(resultThreadMap, result);
                    return responseMapper.apply(result);
                })
                .onErrorReturnItem(-1);
    }

    private void putInThreadMap(Map<Long, List<Integer>> map, int i) {
        map.merge(Thread.currentThread().getId(), singletonList(i), this::merge);
    }

    private List<Integer> merge(List<Integer> a, List<Integer> b) {
        return Stream.concat(a.stream(), b.stream()).collect(Collectors.toList());
    }
}
编辑:

如果您还可以演示如何在中执行此操作,则可获得额外积分

编辑2:
使用project Reactor的解决方案是。

我假设在中,您希望在本平面图中返回的iterable排放之间插入延迟:

.flatMap(i -> {
   log.debug("Processing group: {}.", i);
       return Flowable.fromIterable(i)
           .delay(groupMemberDelaySeconds, SECONDS);
})
在这种情况下,您误解了延迟运算符。它只是在规定的时间内改变排放量。要在每次发射之间插入延迟,可以使用interval observable压缩它

.flatMap(i -> {
   log.debug("Processing group: {}.", i);
       return Flowable.fromIterable(i)
           .zipWith(Flowable.interval(groupMemberDelaySeconds, SECONDS), (item, time) -> item)
})

但是,您需要了解,只有当您能够确定您的可观察对象总是比指定的时间间隔更频繁地生成时,这种方法才有效,否则,您最终可以缓冲间隔发射,这意味着在接下来的几个项目中,一旦它们进入,就会立即从期望的可观测发射,这取决于从间隔可观测缓冲的事件数。当然,有很多方法可以解决这个问题,但这个方法要简单得多,当您使用Iterable时,您可以在合理的范围内确保它不会发生。

我假设,在中,您希望在Iterable的排放之间插入延迟,这在这个平面图中返回:

.flatMap(i -> {
   log.debug("Processing group: {}.", i);
       return Flowable.fromIterable(i)
           .delay(groupMemberDelaySeconds, SECONDS);
})
在这种情况下,您误解了延迟运算符。它只是在规定的时间内改变排放量。要在每次发射之间插入延迟,可以使用interval observable压缩它

.flatMap(i -> {
   log.debug("Processing group: {}.", i);
       return Flowable.fromIterable(i)
           .zipWith(Flowable.interval(groupMemberDelaySeconds, SECONDS), (item, time) -> item)
})

但是,您需要了解,只有当您能够确定您的可观察对象总是比指定的时间间隔更频繁地生成时,这种方法才有效,否则,您最终可以缓冲间隔发射,这意味着在接下来的几个项目中,一旦它们进入,就会立即从期望的可观测发射,这取决于从间隔可观测缓冲的事件数。当然,有一些方法可以解决这个问题,但这一种更简单,当您使用Iterable时,您可以在合理的范围内确保它不会发生。

您可以尝试下面的代码。关键是使用zipWith并结合间隔,确保所有项目的特定时间排放

public static void main(String[] args) {
    Observable<Integer> o1 = Observable.range(1, 3);
    System.out.println("Without delay");
    o1.subscribe(v -> System.out.println(v));

    System.out.println("With delay");
    o1.zipWith(Observable.interval(1, TimeUnit.SECONDS), (a, b)->a ).subscribe(a->System.out.println(a));
    Observable.timer(5, TimeUnit.SECONDS).toBlocking().subscribe();
}

您可以尝试下面的代码。关键是使用zipWith并结合间隔,确保所有项目的特定时间排放

public static void main(String[] args) {
    Observable<Integer> o1 = Observable.range(1, 3);
    System.out.println("Without delay");
    o1.subscribe(v -> System.out.println(v));

    System.out.println("With delay");
    o1.zipWith(Observable.interval(1, TimeUnit.SECONDS), (a, b)->a ).subscribe(a->System.out.println(a));
    Observable.timer(5, TimeUnit.SECONDS).toBlocking().subscribe();
}

rxjava2扩展库包含spanout

以延迟代替延迟


rxjava2扩展库包含spanout

以延迟代替延迟


groupBy及其组的并行处理在哪里?这不是一个完整的解决方案,而是一个示例实现,用于引入所需的延迟。基于此,应该定制问题的完整解决方案。groupBy及其组的并行处理在哪里?好的,这不是一个完整的解决方案,而是一个引入所需延迟的示例实现。基于此,问题的完整解决方案应该是定制的。你可能是对的,我修改了我的评论。我已经迁移到使用ProjectReactor而不是RxJava2,因此无法在代码中添加注释。我试过这个后会回应的。我在我的问题中添加了一个编辑,询问如何在ProjectReactor中执行此操作。你可能是对的,我修改了我的评论。我已经迁移到使用ProjectReactor而不是RxJava2,因此无法在代码中添加注释。我试过这个后会回应的。我在我的问题中添加了一个编辑,询问如何在ProjectReactor中实现这一点。你为什么这么说David?我也在试用ProjectReactor,请看编辑。你认为RxJava2和Reactor 3中最重要的部分都是谁做的?相信我,我理解这种情绪,我已经做到了。我不是在破坏你对这些项目的贡献。但是我希望看到更多的人对维护代码感兴趣,而不是一个人成为瓶颈。在Ben Christensen离开后,RxJava1的开发不是放缓了吗?RxJava没有开发瓶颈,只是在我去年6月领先之前才出现。我想你是在反应堆中寻找FluxdelayElements操作员吧?3.0.5.BUILD-SNAPSHOT,在3.0.4中曾经是call-just-delay,为什么说David?我也在试用ProjectReactor,请看编辑。你认为RxJava2和Reactor 3中最重要的部分都是谁做的?相信我,我理解这种情绪,我已经做到了。我不是在破坏你对这些项目的贡献。但是我希望看到更多的人对维护代码感兴趣,而不是一个人成为瓶颈。在Ben Christensen离开后RxJava1的开发不是放慢了速度吗
在RxJava上没有开发瓶颈,只是在我去年6月领先之前的管理上。我想你们是在反应堆中寻找FluxdelayElements操作员吧?3.0.5.BUILD-SNAPSHOT,在3.0.4中曾经是call-just-delay