Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在执行其他操作之前查找流大小_Java_Concurrency_Java Stream - Fatal编程技术网

Java 在执行其他操作之前查找流大小

Java 在执行其他操作之前查找流大小,java,concurrency,java-stream,Java,Concurrency,Java Stream,在我的程序中,我反复使用Java 8将对象集合简化为单个对象。在整个执行过程中,此集合的大小可能变化很大:从3个对象到数百个对象 public void findInterestingFoo(Stream<Foo> foos) { internalState.update(foos.collect(customCollector())); } public void findInterestingFoo(流式foos){ update(foos.collect(custom

在我的程序中,我反复使用Java 8将对象集合简化为单个对象。在整个执行过程中,此集合的大小可能变化很大:从3个对象到数百个对象

public void findInterestingFoo(Stream<Foo> foos) {
    internalState.update(foos.collect(customCollector()));
}
public void findInterestingFoo(流式foos){
update(foos.collect(customCollector());
}
在优化我的代码和搜索瓶颈的过程中,我在某个点生成了流。这在当时起了作用,因为藏品都相当大。后来,在更改程序的其他部分和参数后,集合变得更小。我意识到不使流并行更有效。这是有道理的:为4个对象在多个线程上分配工作的开销根本不值得。不过,对于数百件物品来说,这是值得的

如果我能只让大的溪流平行,那将非常方便:

public void findInterestingFoo(Stream<Foo> foos) {
    if (isSmall(foos)) {
        internalState.update(foos.collect(customCollector()));
    } else {
        internalState.update(foos.parallel().collect(customCollector()));
    }
}
public void findInterestingFoo(流式foos){
if(isSmall(foos)){
update(foos.collect(customCollector());
}否则{
update(foos.parallel().collect(customCollector());
}
}
当然,当从或创建流时,可以手动执行此操作。也就是说,我们知道流中包含哪些元素,因此可以跟踪这些元素。然而,我对以一种通用的方式解决这个问题很感兴趣,这样无论将什么类型的流传递给
findInterestingFoo
,它都会得到尽可能有效的适当处理

类似的东西可能会有所帮助,但它会在我能够完成之前终止流

我很清楚,流的设计没有设定大小,特别是:

  • 可能是无限的。虽然集合的大小有限,但流不需要。短路操作,如
    limit(n)
    findFirst()
    可允许在有限时间内完成无限流上的计算。-
不过,我想知道在对流执行任何操作之前,是否有任何方法可以确定流中有多少个元素。流真的不知道它是从有限集合创建的吗

__________

一千次。在我的例子中,优化这一点可以将总运行时间从1.5秒提高到0.5秒。

理论上,您可以这样做:

public void findInterestingFoo(Stream<Foo> foos) {
    Spliterator<Foo> sp = foos.spliterator();
    long size = sp.getExactSizeIfKnown();// returns -1 if not known
          // or sp.estimateSize(); // Long.MAX_VALUE means "unknown"
    internalState.update(
        StreamSupport.stream(sp, size > PARALLEL_THRESHOLD)
                     .collect(customCollector()));
}
public void findInterestingFoo(流式foos){
Spliterator sp=foos.Spliterator();
long size=sp.getExactSizeIfKnown();//如果未知,则返回-1
//或sp.estimateSize();//Long.MAX_值表示“未知”
internalState.update(
StreamSupport.stream(sp,大小>并行_阈值)
.collect(customCollector());
}
是一个终端操作,它使用输入流,但您可以传递to来构造具有完全相同属性的流。第二个参数已经告诉我们流是否应该是并行的

理论上

实际上,根据流是否并行,当前流实现将返回不同的
拆分器
实现。这意味着,当调用
spliterator()
之前原始流还没有并行时,将流重新创建为并行流可能会导致无法执行并行处理的流

但是,如果没有中间操作(例如,当您直接传入从集合或数组创建的
时),它确实工作得很好

spliterator()
之前调用,以获得一个支持并行的流,如果您决定这样做,该流可能仍会按顺序运行,在很多情况下都会起作用。但是,如果输入流中存在有状态的中间操作,如
sorted()
,则它们可能会被修复为并行运行,即使您按顺序执行
收集操作(反之亦然)


另一个问题具有根本性。元素的数量实际上并不能说明并行处理是否会带来好处。这确实取决于每个元素的工作负载,这不仅取决于您的终端
collect
操作,还取决于在进入您的方法之前已经链接到流的操作。即使您认为收集器的工作负载已经足够高,可以进行并行处理,也可能是传入流具有诸如或(在有序流上)之类的操作,这些操作通常并行运行得更差,并且需要一个完全不同的阈值


一个更简单的解决方案是让调用者决定,因为调用者知道流的大小和性质。您甚至不需要在方法的签名中添加选项,因为调用方在将流传递给您的方法之前已经可以通过调用流上的
parallel()
sequential()
来做出决定,您可以通过不更改模式来尊重这一点

“流真的不知道它是从有限的集合创建的吗?”-你说的是一个接口,所以答案是:不,一个(通用的)
不知道它是否是从(有限的)源创建的,因为它既不定义
isFinite()
-也不定义
大小()
-method。在您的情况下,性能有多重要?对我来说,这听起来像是几百个元素,无论您是否并行,都只会产生微小的差异。@Turing85当然。但据我所知,没有
SizedStream
接口或任何类似的东西。或者有吗?据我所知,流c由数组创建。stream
只是
stream
s。如果它真的、真的、真的很重要,请添加一个参数,让调用者传递一个提示,说明流是大还是小(或者只是预期是大还是小)。@OleV.V。问题是,这个方法被调用了数千次