Parallel processing 从并行流收集部分结果

Parallel processing 从并行流收集部分结果,parallel-processing,java-8,java-stream,Parallel Processing,Java 8,Java Stream,在Java8中,处理两个并行流中的项目对,如下所示: final List<Item> items = getItemList(); final int l = items.size(); List<String> results = Collections.synchronizedList(new ArrayList<String>()); IntStream.range(0, l - 1).parallel().forEach( i -> {

Java8
中,处理两个并行流中的项目对,如下所示:

final List<Item> items = getItemList();
final int l = items.size();
List<String> results = Collections.synchronizedList(new ArrayList<String>());
IntStream.range(0, l - 1).parallel().forEach(
    i -> {
        Item item1 = items.get(i);
        int x1 = item1.x;
        IntStream.range(i + 1, l).parallel()
            .forEach(j -> {
                Item item2 = items.get(j);
                int x2 = item2.x;
                if (x1 + x2 < 200) return;
                // code that writes to ConcurrentHashMap defined near results
                if (x1 + x2 > 500) results.add(i + " " + j);
            });
    }
);
final List items=getItemList();
final int l=items.size();
列表结果=Collections.synchronizedList(新的ArrayList());
IntStream.range(0,l-1).parallel().forEach(
我->{
Item item1=items.get(i);
int-x1=item1.x;
IntStream.range(i+1,l).parallel()
.forEach(j->{
item2=items.get(j);
int x2=项目2.x;
如果(x1+x2<200)返回;
//写入在结果附近定义的ConcurrentHashMap的代码
如果(x1+x2>500)结果。添加(i+“”+j);
});
}
);
每个流对写入
ConcurrentHashMap
,根据特定条件,它可以通过调用
return终止流执行或它可以写入同步列表

我想让流返回结果,比如
returni+“”+j
,并将这些结果收集到外部的字符串列表中。它应该是部分的,因为必须支持不返回任何内容(如果
x1+x2<200


实现这一点最省时(最快的代码)的方法是什么?

我认为这会更高效(但没有做任何微观基准测试):


但是,如果我真的担心这样做所花费的时间,我会更加关注
列表
实现用于
。甚至可以在进入lambda之前将列表转换为
HashMap
。例如,如果
items
是一个
LinkedList
,那么对lambda的任何改进都可能是无关紧要的,因为
items.get()
会占用所有的时间。

在这个答案中,我将不讨论时间效率,因为存在应该事先处理的正确性问题

正如我在评论中所说的,如果我们对流进行并行化,那么在某个条件之后就不可能停止流的执行。否则,在触发停止条件的对之后,可能有一些已经在执行的对
(i,j)
。 另一个问题是
返回在lambda内部,它所做的就是跳过第二个
if
j
,对于
x1+x2<200
保持,但流将继续
j+1

Java中没有直接的方法来停止流,但是我们可以通过
allMatch
来实现这一点,因为我们可以预期,只要它找到
false
值,它就会短路并以正确的方式返回
false

因此,这将是您的代码的正确版本:

IntStream.range(0, l - 1).allMatch(i -> {
    int x1 = items.get(i).x;
    return IntStream.range(i + 1, l).allMatch(j -> {
        int x2 = items.get(j).x;
        if (x1 + x2 < 200) {
            return false;
        } else {
            if (x1 + x2 > 500) results2.add(i + " " + j);
            return true;
        }
    });
});
在我的版本中,
结果
的内容是:

[0 2, 0 3, 1 2]
使用您的代码(每次执行的顺序和元素不同):


请提供正确的编译代码。您的
结果
被声明为数组,但您使用它就像使用列表一样。ConcurrentHashMap在哪里?你到底在写什么?另外,请提供一个示例输入和所需的输出。现在有点不清楚你想要实现什么。如果
x1+x2>500
,你只是在增加
结果。为什么不使用收集器呢?也。。。据我所知,您不能从这样的foreach返回。在您的特定示例中,并行处理可能不会产生更快的性能。看看这个问题及其最重要的答案:在关心时间效率之前,我认为你应该关心正确性。(1) 如果需要在特定条件下终止流,则无法并行化,否则无法控制执行顺序,并且可能会有对添加到
结果
列表中,这些对逻辑上发生在触发停止条件的对之后
x1+x2<200
。(2) A
返回
这样肯定不是停止流执行的方法。@downvoter:解释和/或改进建议会很有帮助,而且也符合以下礼貌原则:
final List<Item> items = Arrays.asList(
        new Item(200, 0),
        new Item(100, 0),
        new Item(500, 0),
        new Item(400, 0),
        new Item(1, 0));
[0 2, 0 3, 1 2]
[2 4, 2 3, 1 2, 0 3, 0 2]