繁体   English   中英

在并行Java流中处理随机数

[英]Processing random numbers in parallel Java stream

我想从0到50范围内生成5个不同的随机数,然后并行地对它们执行一些操作。 当我写这个程序时,程序永远不会结束:

new Random().ints(0, 50)
            .distinct()
            .limit(5)
            .parallel()
            .forEach(d -> System.out.println("s: " + d));

我试图使用peek调试它。 我有无限数量的c:行,50 d:行,但是零l:s:行:

new Random().ints(0, 50)
            .peek(d -> System.out.println("c: " + d))
            .distinct()
            .peek(d -> System.out.println("d: " + d))
            .limit(5)
            .peek(d -> System.out.println("l: " + d))
            .parallel()
            .forEach(d -> System.out.println("s: " + d));

我的实施有什么问题?

首先,请注意.parallel()更改整个管道的并行状态,因此它会影响所有操作,而不仅仅是后续操作。 在你的情况下

new Random().ints(0, 50)
            .distinct()
            .limit(5)
            .parallel()
            .forEach(d -> System.out.println("s: " + d));

是相同的

new Random().ints(0, 50)
            .parallel()
            .distinct()
            .limit(5)
            .forEach(d -> System.out.println("s: " + d));

您不能仅并行化部分管道。 它是平行还是不平行。

现在回到你的问题。 由于Random.ints是一个无序流,因此选择了distinctlimit无序实现,因此它不是这个问题的重复(问题出现在有序的不同实现中)。 这里的问题在于无序的limit()实现。 为了减少可能的争用,它不检查在不同线程中找到的元素的总数,直到每个子任务获得至少128个元素或上游耗尽(参见实现1 << 7 = 128 )。 在你的情况下,上游distinct()发现只有50个不同的元素,拼命遍历输入,希望找到更多,但下游limit()不发信号停止处理,因为它想要在检查之前是否收集至少128个元素达到限制(由于限制小于128,因此不是很聪明)。 所以要使这个东西工作,你应该至少选择(128 *个CPU数量)不同的元素。 在我的4核机器上使用new Random().ints(0, 512)成功,而new Random().ints(0, 511)卡住了。

为了解决这个问题,我建议按顺序收集随机数并在那里创建一个新流:

int[] ints = new Random().ints(0, 50).distinct().limit(5).toArray();
Arrays.stream(ints).parallel()
      .forEach(d -> System.out.println("s: " + d));

我假设你想要执行一些昂贵的下游处理。 在这种情况下,并行生成5个随机数并不是很有用。 顺序执行时,此部分将更快。

更新:提交了错误报告并提交了补丁

你的ints(0, 50)电话( ints(0, 50)

返回有效无限的伪随机int值流,每个值符合给定的原点(包括)和绑定(不包括)。

我原本以为是未IntStream是问题所在,但我重复了这个问题。

new Random().ints(0, 50)
            .distinct().limit(5)
            .parallel().forEach(a -> System.out.println(a));

进入一个无限循环,而

new Random().ints(0, 50)
            .distinct().limit(5)
            .forEach(a -> System.out.println(a));

完成正确。

我的Stream知识不是很好,我可以解释它,但显然并行化不能很好地发挥作用(可能是由于无限的流)。

您尝试做的最接近的选择可能是使用iterateunordered

Random ran = new Random();
IntStream.iterate(ran.nextInt(50), i -> ran.nextInt(50))
    .unordered()
    .distinct()
    .limit(5)
    .parallel()
    .forEach(System.out::println);

使用无限流和distinct parallel可能是昂贵的或导致没有响应。 有关详细信息,请参阅API注释此问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM