当前位置: 首页 > 面试题库 >

在多线程的情况下,最好使用性能限制在流上使用限制

端木宏才
2023-03-14
问题内容

我观看了JoséPaumard在InfoQ上的演讲:http : //www.infoq.com/fr/presentations/jdk8-lambdas-streams-
collectors
(法语)

事情是我坚持这一点。要使用流 线程收集1M Long 我们可以这样做:

Stream<Long> stream = 
  Stream.generate(() -> ThreadLocalRandom.current().nextLong()) ;

List<Long> list1 = 
  stream.parallel().limit(10_000_000).collect(Collectors.toList()) ;

但是考虑到线程始终在检查上述限制的事实会影响性能。

在那次演讲中,我们还看到了第二个解决方案:

Stream<Long> stream = 
  ThreadLocalRandom.current().longs(10_000_000).mapToObj(Long::new) ;

List<Long> list = 
  stream.parallel().collect(Collectors.toList()) ;

并且似乎是更好的性能明智的选择。

所以这是我的问题:为什么第二个代码更好,并且有更好或更便宜的方法呢?


问题答案:

这是 依赖实现的 限制。对于并行性能的关注,开发人员必须了解的一件事是,可预测的流大小通常有助于并行性能,因为它们可以平衡工作负载。

这里的问题是,通过Stream.generate()和创建的无限流的组合limit()不会产生具有可预测大小的流,尽管它对我们而言似乎是完全可预测的。

我们可以使用以下辅助方法对其进行检查:

static void sizeOf(String op, IntStream stream) {
    final Spliterator.OfInt s = stream.spliterator();
    System.out.printf("%-18s%5d, %d%n", op, s.getExactSizeIfKnown(), s.estimateSize());
}

然后

sizeOf("randoms with size", ThreadLocalRandom.current().ints(1000));
sizeOf("randoms with limit", ThreadLocalRandom.current().ints().limit(1000));
sizeOf("range", IntStream.range(0, 100));
sizeOf("range map", IntStream.range(0, 100).map(i->i));
sizeOf("range filter", IntStream.range(0, 100).filter(i->true));
sizeOf("range limit", IntStream.range(0, 100).limit(10));
sizeOf("generate limit", IntStream.generate(()->42).limit(10));

将打印

randoms with size  1000, 1000
randoms with limit   -1, 9223372036854775807
range               100, 100
range map           100, 100
range filter         -1, 100
range limit          -1, 100
generate limit       -1, 9223372036854775807

因此,我们可以看到,某些来源喜欢Random.ints(size)IntStream.range(…)产生具有可预测大小的流,而某些中间操作map则可以携带信息,因为他们知道大小不受影响。其他人喜欢filter并且limit不传播尺寸(作为已知的准确尺寸)。

显然,filter无法预测元素的实际数量,但是它提供了源大小作为估计值,这是合理的,因为这是可以通过过滤器的最大元素数量。

相反,limit即使源具有精确的大小,当前的实现也不提供大小,并且我们知道可预测的大小很简单min(source size, limit)。取而代之的是,它甚至报告了一个毫无意义的估计大小(源的大小),尽管事实是,结果大小永远不会超过限制。在无限流的情况下,我们还Spliterator面临其他障碍,即流所基于的接口无法报告它是无限的。在这些情况下,无限的流量+极限Long.MAX_VALUE作为估计返回,这意味着“我什至无法猜测”。

因此,根据经验,在当前的实现中,程序员应避免limit在有可能预先在流源处指定所需大小的情况下使用。但是由于limit有序
并行流(不适用于random或generate)的情况下也具有明显的(已记录的)缺点,因此大多数开发人员limit还是会避免使用。



 类似资料:
  • 我们可以创建一个具有无限数据源(例如健康信号)的Java流吗?

  • 我有一个tomcat服务器,可以处理一些rest API请求。这个tomcat崩溃是由于某些输入中的一个特定rest请求内存不足导致的,这会导致大量堆大小的使用,从而导致所有站点崩溃。 我想限制这个Rest请求内存使用我怎么能做到呢?我通常想保护tomcat免受大内存使用请求崩溃的影响。我怎么能做到呢?也许以某种方式限制所有线程最大堆大小?

  • Java Streams同时使用和方法,这两种方法分别返回流的排序版本和仅返回流中指定数量项的流。连续应用这些操作时,例如: 排序是以排序项的方式执行的,还是对整个列表进行排序?换句话说,如果是固定的,那么这个操作是否在中?留档不会单独指定这些方法的性能,也不会相互关联指定这些方法的性能。 我提出这个问题的原因是,这些操作的明显必要实现是排序然后限制,这需要时间。但是这些操作可以一起在中执行,智能

  • 如果我使用SDL,我会有任何已知的限制吗?(我经常读到SDL有点僵硬)

  • 4如果类成员访问中的id-expression是窗体的限定id-id 首先在对象表达式([class.member.lookup])的类中查找或运算符后面的,如果找到,则使用名称。否则,它将在整个后缀表达式的上下文中查找。 因此,首先必须在struct中查看,但在那里是不明确的。事实上,Clang报告了一个错误: