如何在Java并行流中使用print(“\r”progressMessage)?

如何在Java并行流中使用print(“\r”progressMessage)?,java,parallel-processing,java-stream,Java,Parallel Processing,Java Stream,我试图通过编写以下内容来显示parallelStream的进度 int total=myList.size(); AtomicInteger counter=new AtomicInteger(0); List<String> myResult=IntStream.range(0, total) .parallel() .mapToObj(i-> modify(myList.get(i)))

我试图通过编写以下内容来显示parallelStream的进度

int total=myList.size();
AtomicInteger counter=new AtomicInteger(0);

List<String> myResult=IntStream.range(0, total)
                    .parallel()
                    .mapToObj(i-> modify(myList.get(i)))
                    .peek(i->System.out.print("\r"+(counter.getAndIncrement()*100/total)+"%"))
                    .collect(toList());
inttotal=myList.size();
AtomicInteger计数器=新的AtomicInteger(0);
List myResult=IntStream.range(0,总计)
.parallel()
.mapToObj(i->modify(myList.get(i)))
.peek(i->System.out.print(“\r”+(counter.getAndIncrement()*100/总计)+“%”)
.collect(toList());

我的问题来自“\r”。考虑到它是并行的,当并发事件发生时,真正转到行开头所需的“\r”数量可能会有所不同。因此,我有时可以阅读“70%71%”·····························

int total = myList.size();
AtomicInteger counter = new AtomicInteger(0);
ScheduledExecutorService es = Executors.newScheduledThreadPool(1);

ScheduledFuture<?> f = es.scheduleWithFixedDelay(new Runnable() {
    int lastReported = -1;
    public void run() {
        int newValue = counter.get();
        if(newValue != lastReported) {
            lastReported = newValue;
            System.out.append("\r"+newValue*100/total+"%").flush();
        }
    }
}, 100, 100, TimeUnit.MILLISECONDS);

List<String> myResult = IntStream.range(0, total)
    .parallel()
    .mapToObj(i -> modify(myList.get(i)))
    .peek(i -> counter.incrementAndGet())
    .collect(toList());

f.cancel(true);
es.shutdown();
System.out.print("\r100%");
inttotal=myList.size();
AtomicInteger计数器=新的AtomicInteger(0);
ScheduledExecutorService es=执行者。newScheduledThreadPool(1);
ScheduledFuture f=es.scheduleWithFixedDelay(新的可运行(){
int lastreepted=-1;
公开募捐{
int newValue=counter.get();
如果(新值!=上次报告){
lastReported=新值;
System.out.append(“\r”+newValue*100/total+“%”)flush();
}
}
},100100,时间单位为毫秒);
List myResult=IntStream.range(0,总计)
.parallel()
.mapToObj(i->modify(myList.get(i)))
.peek(i->counter.incrementAndGet())
.collect(toList());
f、 取消(真);
es.shutdown();
系统输出打印(“\r100%”);
现在,打印是由一个线程一致完成的。这种分离解决了更多的问题。 对每个元素执行打印操作将大大降低实际处理速度。通过使用计划的打印作业,您可以自己控制开销,也就是说,您不需要打印速度超过人的阅读速度,并且如果百分比自上次更新以来没有变化,您也不需要执行昂贵的打印操作


请注意,到那时,所有元素都通过了
peek
操作,流操作还没有完全完成(至少有一个合并操作挂起),但这是使用当前API可以得到的最佳进度估计。

为什么要自己添加返回?println怎么了?println转到下一行。我想用新的百分比代替旧的百分比。在同一条线上,嗯?你们不能这样做。@Michael为什么不能,我的意思是用
\\r
跳到当前行的开头?(在Linux上)工作得非常好。你肯定有一个终端可以接受这一点,不像Eclipse控制台,也可能是Windows控制台。@CarlosHeuberger好的,我刚查过。我不理解单独使用回车时的确切语义。看起来它可能会在Windows上工作。我希望,这个程序足够简单,可以证明这不是程序的问题。仔细想想,原始代码的
System.out.print
在内部使用了同步,因此它也不应该表现出这种行为,这表明问题出在其他地方。尽管如此,在您的原始代码中,操作可能会相互重叠,从而导致打印的百分比不连续,而且还存在性能问题,因此您仍然应该采纳我的建议。但印刷问题肯定在其他地方。如前所述,它在Windows控制台上工作得很顺利。既然是“计数器”递增并打印,而不是“i”,它怎么会导致不连续的百分比呢?啊,我确实有单调的价值观(我想这就是你的意思)。我将尝试创建一个测试方法“modify()”,将问题与我的代码的其余部分隔离开来,然后再与您联系。@Myoch:
counter
以原子方式进行查询和更新。之后,您将使用
int
值构造一个字符串,然后将其传递给
System.out.print
。构造一个字符串需要一些时间,在此期间,另一个稍后更新了
计数器的线程可能会更快地完成该字符串的构造(因为线程调度是不可预测的),并打印其较高的数字。然后,第一个线程用较小的数字完成其字符串构造并打印它,用较大的数字覆盖消息。