单流和多用户

时间:2018-01-09 00:40:43

标签: rx-java reactive-programming rx-java2 java-9 reactive-streams

我正在用Java9反应流和RxJava2测试水域。我真的不喜欢任何一个,但我正在寻找一些指导,如果这是可能的。

  1. 我正在创建一个预配置数量的订阅者,如下所示:

    for(int i = 0; i<MAX_SUBSCRIBERS; i++) {  
         System.out.println("Creating subscriber: " + i);  
         publisher.subscribe(new MySubscriber<>(i + "-subscriber"));   
    }
    
  2. 我正在读取目录中的文件列表,以便并发上传到某些第三方系统。

    Stream<Path> paths = Files.list(Paths.get("/my/dir/with/files"));
    paths
    .filter((Files::isRegularFile))
    .forEach(pathName -> publisher.submit(pathName.toString()));
    
  3. 我收到以下输出:

        0-subscriber: /my/dir/with/files/test0.txt received in onNext
        0-subscriber: /my/dir/with/files/test1.txt received in onNext
        1-subscriber: /my/dir/with/files/test0.txt received in onNext
        1-subscriber: /my/dir/with/files/test1.txt received in onNext
    

    理想情况下,我们应该看到以下行为。每个订阅者应该在一个唯一的文件上执行工作。

        0-subscriber: /my/dir/with/files/test0.txt received in onNext
        1-subscriber: /my/dir/with/files/test1.txt received in onNext
    

    这可能吗?任何提示都会很棒!

3 个答案:

答案 0 :(得分:2)

这是一个评论,但它变得太长了。但是,这不是一个真正的答案,因为我没有反应流专家。这是一些值得思考的东西。

我的理解是每个订阅者都看到所有发布的元素,并且订阅者应该彼此独立(我说这不包括显式协调)。如果文件之间存在实质性差异(例如一个是PDF而另一个TXT),则订阅者可能决定仅对其构建的类型进行操作,但除此之外,每个文件都应处理每个元素。

看起来您正在尝试将工作负载分散到多个订阅者,我假设这些订阅者在不同的线程中运行。这肯定是现有并发构造处理得非常好的东西。例如,请查看ExecutorService

也就是说,如果您正在构建一个更大的流管道,我认为没有反对在单个订户中封装distribute-file-processing-across-threads部分的论据。它甚至可能是发布者本身,一旦完成就会发布处理每个文件的结果。

最后一个警告:也许RxJava对于这个特定的用例有一些东西。我很想读其他答案。

答案 1 :(得分:2)

Java 9 Flow API由4个接口和SubmissionPublisher类组成,它将每个提交的值分派给它的所有Subscriber。目前没有JDK工具支持您的数据流。

相比之下,RxJava是一个包含数百个运算符的丰富流畅的库,您可以在其中执行并行处理而无需重复:

    ParallelFlowable<Path> pf = 
            Flowable.<Path, Stream<Path>>using(
                () -> Files.list(Paths.get("/my/dir/with/files")),
                files -> Flowable.fromIterable((Iterable<Path>)() -> files.iterator()),
                AutoCloseable::close
            )
            .parallel(2)
            .runOn(Schedulers.computation())
            .filter(Files::isRegularFile);

pf.subscribe(new Subscriber[] {
    new MySubscriber<>("0-subscriber"),
    new MySubscriber<>("1-subscriber"),
});

答案 2 :(得分:1)

发布者可以有两种:多播和单播。组播发布者向每个订阅者提供完整的消息集,而单播发布者将每个消息路由给单个订阅者。 SubmissionPublisher被编程为多播,在其文档中有介绍。

您可以在我的图书馆DF4J中找到单播发布者的实现。寻找接口org.df4j.protocol.Flow.Publisher的实现,该接口扩展了org.reactivestreams.Publisher