- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现 Java 并行流有一些令人惊讶的行为。我自己制作了Spliterator
,并且生成的并行流被分割,直到每个流中只有一个元素。这似乎太小了,我想知道我做错了什么。我希望我可以设置一些特征来纠正这个问题。
这是我的测试代码。 Float
这只是一个虚拟的有效载荷,我真正的流类要复杂一些。
public static void main( String[] args ) {
TestingSpliterator splits = new TestingSpliterator( 10 );
Stream<Float> test = StreamSupport.stream( splits, true );
double total = test.mapToDouble( Float::doubleValue ).sum();
System.out.println( "Total: " + total );
}
此代码将不断拆分此流,直到每个
Spliterator
只有一个元素。这似乎太高效了。
run:
Split on count: 10
Split on count: 5
Split on count: 3
Split on count: 5
Split on count: 2
Split on count: 2
Split on count: 3
Split on count: 2
Split on count: 2
Total: 5.164293184876442
BUILD SUCCESSFUL (total time: 0 seconds)
这是
Spliterator
的代码.我主要关心的是我应该使用什么特性,但也许其他地方有问题?
public class TestingSpliterator implements Spliterator<Float> {
int count;
int splits;
public TestingSpliterator( int count ) {
this.count = count;
}
@Override
public boolean tryAdvance( Consumer<? super Float> cnsmr ) {
if( count > 0 ) {
cnsmr.accept( (float)Math.random() );
count--;
return true;
} else
return false;
}
@Override
public Spliterator<Float> trySplit() {
System.err.println( "Split on count: " + count );
if( count > 1 ) {
splits++;
int half = count / 2;
TestingSpliterator newSplit = new TestingSpliterator( count - half );
count = half;
return newSplit;
} else
return null;
}
@Override
public long estimateSize() {
return count;
}
@Override
public int characteristics() {
return IMMUTABLE | SIZED;
}
}
那么我怎样才能让流被分成更大的 block 呢?我希望在 10,000 到 50,000 附近会更好。
null
来自
trySplit()
方法,但这似乎是一种倒退的方式。系统似乎应该对核心数量、当前负载以及使用流的代码的复杂程度有一些概念,并相应地进行自我调整。换句话说,我希望流 block 大小是外部配置的,而不是由流本身在内部固定的。
StreamSupport
最终会停止 split 。
StreamSupport
当流大小达到 2 时停止拆分(我在屏幕上看到的最后一行是
Split on count: 4
)。
Spliterator
s 创建。以下是更改:
public static void main( String[] args ) {
TestingSpliterator splits = new TestingSpliterator( 100 );
Stream<Float> test = StreamSupport.stream( splits, true );
double total = test.mapToDouble( Float::doubleValue ).sum();
System.out.println( "Total Spliterators: " + testers.size() );
for( TestingSpliterator t : testers ) {
System.out.println( "Splits: " + t.splits );
}
}
和
TestingSpliterator
的 Actor :
static Queue<TestingSpliterator> testers = new ConcurrentLinkedQueue<>();
public TestingSpliterator( int count ) {
this.count = count;
testers.add( this ); // OUCH! 'this' escape
}
这段代码的结果是第一个
Spliterator
被拆分 5 次。下一个
Spliterator
被拆分 4 次。下一组
Spliterators
split 3次。等等。结果是 36
Spliterators
制作完成,流被分成尽可能多的部分。在典型的桌面系统上,这似乎是 API 认为最适合并行操作的方式。
StreamSupport
类(class)正在做正确的事,不要担心,要快乐。对我来说,部分问题是我正在对非常小的流大小进行早期测试,我对拆分的数量感到惊讶。不要自己犯同样的错误。
最佳答案
你从错误的角度看它。该实现没有拆分“直到每个拆分器都有一个元素”,而是拆分“直到有十个拆分器”。
单个拆分器实例只能由一个线程处理。拆分器在开始遍历后不需要支持拆分。因此,任何事先未使用的拆分机会都可能导致之后的并行处理能力受限。
请务必记住,Stream 实现收到了 ToDoubleFunction
。工作量未知¹。不知道就这么简单Float::doubleValue
在你的情况下。它可能是一个需要花一分钟时间评估的函数,然后每个 CPU 核心都有一个分离器是正确的。即使拥有多个 CPU 内核也是一种有效的策略,可以处理某些评估花费的时间明显长于其他评估的可能性。
初始拆分器的典型数量将是“CPU 核心数”× 4,尽管稍后当更多关于实际工作负载的知识存在时,这里可能会进行更多拆分操作。当您的输入数据少于该数字时,将其拆分直到每个拆分器只剩下一个元素就不足为奇了。
你可以试试new TestingSpliterator( 10000 )
或 1000
或 100
一旦实现假设有足够的 block 来保持所有 CPU 内核忙碌,就会看到拆分的数量不会发生显着变化。
由于您的拆分器也不了解消费流的每个元素的工作负载,因此您不必担心这一点。如果您可以顺利地支持拆分为单个元素,那就这样做吧。
¹ 但是,对于没有操作被链接的情况,它没有特殊的优化。
关于Java Spliterator 不断拆分并行流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66699742/
我在想问题的答案:How to test for null keys on any Java map implementation? 我的第一个想法是检查 map 键集的 Spliterator 是否
在 Java 1.8.0_25 发布到荒野之后有一个有趣的情况......我相信我的问题的根源主要与接口(interface)中“默认”实现的新(到 1.8)特性有关。 我正在开发的应用程序目前的目标
我发现 Java 并行流有一些令人惊讶的行为。我自己制作了Spliterator ,并且生成的并行流被分割,直到每个流中只有一个元素。这似乎太小了,我想知道我做错了什么。我希望我可以设置一些特征来纠正
我对我的所有研究感到有点困惑。我有一个名为 TabularResultSet 的自定义界面(为了举例,我已经淡化了它)它遍历任何本质上是表格的数据集。它有一个类似于迭代器的 next() 方法,它可以
我遇到了流的 dropWhile 或 takeWhile 方法的问题,因为 spliterator 正在跳过特定模式奇数或偶数中的文本部分。应该怎样处理文本的所有部分?我的方法在这里: void re
https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html SIZED Characteristic value sign
我正在玩 Java 8 Spliterator并创建了一个将斐波那契数字流式传输到给定的 n。所以对于斐波那契数列 0, 1, 1, 2, 3, 5, 8, ... n fib(n) -----
我想使用 Stream 并行处理一组未知数量的异构远程存储 JSON 文件(文件数量预先未知)。这些文件的大小差异很大,从每个文件 1 个 JSON 记录到某些其他文件中的 100,000 条记录。在
这可能是非常基本的,但我不是 Java 人。这是我的处理代码,它只是打印和 hibernate : private static void myProcessings(int value)
我正在查看 Spliterator 的文档,根据它,Spliterator 不是线程安全的: Despite their obvious utility in parallel algorithms,
我最近发现了一个错误 StreamSupport.intStream(/* a Spliterator.ofInt */, true) .limit(20) 调用 Spliterator.of
我在 java.util.Spliterator (Java 8) 中偶然发现了一个有趣的细节。 方法 trySplit() 应该返回 Spliterator 的实例或 null,如果它不能被拆分。
我明白 there is overhead in setting up并行 Stream 的处理,如果项目很少或每个项目的处理速度很快,则单线程中的处理速度更快。 但是,trySplit() 是否有类
stream.spliterator() 是否隐式关闭了 stream,还是之后需要显式关闭它? Stream stream = Stream.of("a", "b", "c"); Spliterat
在Collection的源代码中,我想知道为什么@Override使用注释。 spliterator()方法不是来自 Iterable ,和Object也没有。 public interface Co
我正在使用 Java 8 流。 当我使用 spliterator 添加到 map 时,出现重复键异常,但使用标准 for 循环不会引发异常。 // This works Map myMap = new
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我读了一些关于如何创建有限的 Stream 的问题( Finite generated Stream in Java - how to create one? , How do streams sto
我将流拆分器直接用于我正在编写的库中的低级操作。最近,当我进行流拆分器和交错 tryAdvance/trySplit 调用时,我发现了非常奇怪的行为。这是演示问题的简单代码: import java.
我注意到使用 Guava 的 Iterables.partition(collection, partitionSize).spliterator() 生成的拆分器表现得很奇怪。 在生成的拆分器上执行
我是一名优秀的程序员,十分优秀!