我正在用Java9反应流和RxJava2测试水域。我真的不喜欢任何一个,但我正在寻找一些指导,如果这是可能的。
我正在创建一个预配置数量的订阅者,如下所示:
for(int i = 0; i<MAX_SUBSCRIBERS; i++) {
System.out.println("Creating subscriber: " + i);
publisher.subscribe(new MySubscriber<>(i + "-subscriber"));
}
我正在读取目录中的文件列表,以便并发上传到某些第三方系统。
Stream<Path> paths = Files.list(Paths.get("/my/dir/with/files"));
paths
.filter((Files::isRegularFile))
.forEach(pathName -> publisher.submit(pathName.toString()));
我收到以下输出:
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
这可能吗?任何提示都会很棒!
答案 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