通过Java中的套接字发送(并行)流

时间:2016-04-03 13:43:41

标签: java sockets parallel-processing java-8 java-stream

我正在尝试使用Java 8 map-reduce框架在java中编写一个分布式Map-reduce程序,该框架具有以下设计:

一个客户端将数据发送到3个Mappers(每个都是不同的机器/独立Java应用程序)。映射器通过从数据列表中创建parallelStream()来并行处理数据。

现在每个映射器都应该在其parallelStream上调用.map(...)。然后,想法是将映射的数据发送到另一个节点Reducer。

reducer将获取Stream并在其上调用.reduce(...),最后.get()获取最终结果,然后发送回客户端。

如果我在同一个程序上调用.map(...).reduce(...).get(),我的程序可以工作,但我希望能够有一个单独的reducer节点。

由于我是套接字编程和使用Java 8的新手,我在通过Socket发送流时遇到了麻烦,因为它抛出了“java.io.NotSerializableException:java.util.stream.ReferencePipeline $ 3”我尝试使用WriteObject编写流。

这里最好的方法是什么?我可以将流转换为其他内容,发送它然后再在我的Reducer节点上将其转换为流吗?是否有更好的方式来发送流而不是通过ObjectOutputStream

非常感谢任何想法。非常感谢你!

P.S。:流是Stream<Map<String, Integer>>

1 个答案:

答案 0 :(得分:0)

一种方法是使用将数据推入套接字的forEach来终止map节点。如果集合可能非常大(或理论上无限大),这种策略优于集合方法;它的空间效率很高,它是缓冲的,下游节点没有空闲等待收集过程完成。

接下来为Spliterator中的reduce节点包装套接字读取器(扩展AbstractSpliterator)。 Spliterator的tryAdvance方法从套接字读取数据,并通过调用者提供的Consumer使其可用于流。当没有更多数据(您的流结束标记,流套接字结束或套接字异常)时,tryAdvance返回false。 AbstractSpliterator.trySplit实现了有限的并行性。

使用StreamSupport.stream(Spliterator spliterator,boolean parallel)从Spliterator实现构造流。您的reduce操作会从此流中提取数据。

您可以保留套接字,并且您的流末尾标记可能更像是消息结束标记(让我想起管道中的批处理猪)。