Java 8 查看并行流以增加计数器

Java 8 查看并行流以增加计数器,java-8,java-stream,Java 8,Java Stream,我有一个并行处理文件的管道,但我对peek函数有点怀疑 File file = articles.parallelStream( ) .map( article -> { String fileName = processer.getFriendlyName( article, locale ); currentCount.incrementAndGet(

我有一个并行处理文件的管道,但我对peek函数有点怀疑

File file = articles.parallelStream( )
                    .map( article -> {
                        String fileName = processer.getFriendlyName( article, locale );
                        currentCount.incrementAndGet();
                        return new ImmutablePair<>( fileName, converted );
                    } )
                    .peek( pair -> statusMessageSender.sendStatusMessage( totalCount, currentCount.get(), pair.getKey( ) ) )
                    .collect( new Archiver( archivePath ) );
File File=articles.parallelStream()
.map(文章->{
字符串文件名=processer.getFriendlyName(文章,语言环境);
currentCount.incrementAndGet();
返回新的ImmutablePair(文件名,已转换);
} )
.peek(pair->statusMessageSender.sendStatusMessage(totalCount、currentCount.get()、pair.getKey())
.收集(新存档者(存档路径));
通过阅读javadocs,我不能完全确定应该发送当前进度状态的计数器是否正在工作(基本上,在这里的文档中寻找保证)

对于平行流管道,可以在任何位置调用该操作 时间和在任何线程中,元素由 上游操作

在我看来,无论文件名相对于处理顺序是否正确,观察者都会获得当前计数,这很好。但最终,我会不相信这一点,并在sendStatusMessage的接收器上实现同步


最后,我正在寻找一种以并行流发送状态的方法,有什么想法吗

起初,讨论中有很多关于peek的内容,以及我为什么要将消息传递部分从映射表达式中分离出来。这更多的是一个风格问题,因为我倾向于使用映射函数进行映射,仅此而已

我明白为什么人们会为peek辩护或反对它。但按钮行的作用是消耗一个值并在管道中传递它。因此,当我在寻找一个共同的行为(传递消息)时,peek函数看起来很完美

在并行流中,问题是无法预测实际调用peek的时间。但有两个方面需要考虑:何时发送消息与手头的问题无关,消息本身可以随时发送

最后,计数器可能也在窥视部分,消息接收器是这里唯一真实的因素。消息接收器可以有自己的计数器,或者只考虑在时间帧中接收到的最高值。 Button line(按钮行)问题以围绕peek的建议开始,最后以以下内容结束: 就功能而言,peek函数可以很好地完成它的工作:主要是因为管道中的序列没有排序

但是,消息使用者会告诉我们它是否能够正确地使用该消息。鉴于只有一个使用者在使用该信息,而其他使用者没有,最终的结论是,我们在协议设计中遇到了问题,而不是在peek函数周围。我们从std消息中删除了计数器,问题就消失了。peek可以安全地用于解决这个问题,是的,它可以,但是

因此: 它可以是:

File archive = articles.parallelStream( )
                       .map( article -> {
                           File converted = converter.getFile( ... );
                           String fileName = converter.getFriendlyName( ... );
                           return new ImmutablePair<>( fileName, converted );
                       } )
                       .peek( pair -> statusMessageSender.sendStatusMessage( pair.getKey() ) )
                       .collect( new Archiver( archivePath, deleteArchivedFiles ) );
File archive=articles.parallelStream()
.map(文章->{
File converted=converter.getFile(…);
字符串文件名=converter.getFriendlyName(…);
返回新的ImmutablePair(文件名,已转换);
} )
.peek(pair->statusMessageSender.sendStatusMessage(pair.getKey()))
.collect(新归档程序(归档路径、删除归档文件));
或:

File archive=articles.parallelStream()
.map(文章->{
File converted=converter.getFile(…);
字符串文件名=converter.getFriendlyName(…);
返回新的ImmutablePair(文件名,已转换);
} )
.peek(pair->statusMessageSender.sendStatusMessage(currentCount.incrementAndGet(),pair.getKey())
.collect(新归档程序(归档路径、删除归档文件));

但最终还是关于协议,而不是peek。peek肯定可以使用,而问题的非有序性是它可以使用的原因。(感谢您在这方面的帮助)

我觉得很好!Peek无疑是一个不错的选择,尽管您应该使用
.Peek(pair->statusMessageSender.sendStatusMessage(totalCount,currentCount.incrementAndGet(),pair.getKey())
。这对你不起作用吗?它起作用了,我只是担心它在这里起作用是偶然的。我感兴趣的是发送两条消息,由于顺序的关系,状态消息可能会减少。该
文章列表中有多少文章?因为调用
parallelStream
可能根本不会并行执行流。不,这不是一种正确的方法。你的地图会增加一个计数器,然后你的眼睛会看到它。因此,如果4个线程并行执行映射函数,那么4个线程执行peek consomer,您将发送相同的计数器值4次。计数器值(由incrementAndGet()返回)应该是映射函数返回的对象的一部分。使用
incrementAndGet
的结果确实是关键(即不要使用
get
,这会给其他线程增加它的机会)。将您的配对扩展为三元组,或者将消息作为
映射的一部分发送。
File archive = articles.parallelStream( )
                       .map( article -> {
                           File converted = converter.getFile( ... );
                           String fileName = converter.getFriendlyName( ... );
                           return new ImmutablePair<>( fileName, converted );
                       } )
                       .peek( pair -> statusMessageSender.sendStatusMessage( currentCount.incrementAndGet(), pair.getKey() ) )
                       .collect( new Archiver( archivePath, deleteArchivedFiles ) );