当前位置: 首页 > 知识库问答 >
问题:

不可分裂的分裂器

公良天逸
2023-03-14

我试图了解Spliterator是如何工作的,以及拆分器是如何设计的。我认识到trySplit()可能是Spliterator更重要的方法之一,但是当我看到一些第三方Spliterator实现时,有时我看到他们的拆分器无条件地为trySplit()返回null。

问题:

  1. 普通迭代器和无条件返回null的拆分器有何不同?这样的分裂者似乎违背了分裂的目的

共有3个答案

林雅畅
2023-03-14

除了拆分支持之外,还有更多优势:

>

  • 迭代逻辑包含在单个tryAdvance方法中,而不是分散在两种方法中,如hasNext、next。将逻辑分解到两个方法上会使许多迭代器实现复杂化,因为这通常意味着hasNext方法必须执行实际的查询尝试,该查询尝试可能会产生一个值,然后必须为后续的调用记住该值。同时,也必须记住这个查询的事实,无论是显式的还是隐式的。

    如果保证总是以典型的交替方式调用hasNext,那么就更容易了,然而,没有这样的保证。

    一个例子是BufferedReader。readLine()具有简单的tryAdvance逻辑。包装迭代器必须在hasNext实现中调用该方法,并记住下一次调用的行。(具有讽刺意味的是,当前的BufferedReader.stream()实现确实实现了如此复杂的迭代器,它将被包装到拆分器中,而不是直接实现更简单的拆分器。“我不熟悉这个”问题似乎不应低估)

    估计大小();拆分器可以返回可用于预分配资源的剩余项目的估计值(甚至确切数量)。这可以提高效率。

    特征()<代码>拆分器可以提供有关其内容或行为的附加信息。除了告诉估计的大小是否是准确的大小之外,您还可以了解是否可以看到null值,是否有定义的遭遇顺序或所有值都不同。特定算法可以利用这一点。显然,流API是这些算法的组合,在计划创建(或支持创建)流时可以利用这些算法并有选择,实现尽可能多的元信息的拆分器比实现稍后打包的迭代器更好。

  • 终波涛
    2023-03-14

    拆分器的目的之一是能够拆分,但这不是唯一的目的。另一个主要目的是作为一个支持类来创建您自己的流。创建流源的一种方法是实现自己的拆分器并将其传递给StreamSupport。流。最简单的方法通常是编写一个无法拆分的拆分器。这样做会强制流按顺序执行,但这对于您尝试执行的任何操作都是可以接受的。

    在其他情况下,编写不可拆分的Spliterator是有意义的。例如,在OpenJDK中,有一些实现,如emptySpliterator,不包含任何元素。当然它不能被拆分。类似的情况是只包含一个元素的单例拆分器。它也不能被拆分。两种实现都无条件地从trySplit返回null

    另一种情况是,编写不可拆分的Spliterator既简单又有效,而实现可拆分的Spliterator所需的代码量令人望而却步。(至少,不值得将一个代码写入Stack Overflow答案。)例如,从这个答案中查看示例Spliterator。这里的情况是,Spliterator实现想要包装另一个Spliterator并做一些特殊的事情,在这种情况下检查它是否为空。否则它只会将所有内容委托给包装好的Spliterator。使用不可拆分的Spliterator做这件事非常容易。

    注意,在那个答案中有讨论,在我对同一个问题的回答中,在那个答案上的评论,在我的答案上的评论线程,关于如何制作一个可拆分(即并行就绪)的拆分器。但实际上没有人编写代码来进行拆分。:-)根据您希望从原始流中保留多少惰性以及您希望的并行效率,编写可拆分拆分器可能会变得相当复杂。

    据我估计,通过编写迭代器而不是拆分器来完成这类工作会更容易一些(如我上面提到的回答)。原来是分裂器。spliteratorUnknownSize可以提供有限的并行性,即使是从迭代器中,迭代器显然是一个纯序列构造。它在迭代器中实现,迭代器从迭代器中提取多个元素并批量处理它们。不幸的是,批量大小是硬编码的,但至少在某些情况下,这为并行处理从迭代器中提取的元素提供了机会。

    汪理
    2023-03-14

    正如您所说,虽然Spliterator相对于Iterator的主要优势是它的trySplit()方法允许它并行化,但还有其他显着优势:

    http://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html

    拆分器API旨在通过支持分解和单元素迭代,支持除顺序遍历外的高效并行遍历。此外,通过拆分器访问元素的协议被设计为比迭代器施加更小的每元素开销,并避免为hasNext()和next()使用单独方法所涉及的固有竞争。

    此外,可以使用StreamSupport将拆分器直接转换为流。stream来利用Java8的流。

     类似资料:
    • 本文向大家介绍SQL 分裂,包括了SQL 分裂的使用技巧和注意事项,需要的朋友参考一下 示例 使用字符分隔符拆分字符串表达式。请注意,这STRING_SPLIT()是一个表值函数。 结果:            

    • 只是为了澄清事情,我知道正确的代码是: 但我的问题是关于“错误”代码的内部工作。拉库是怎么得出那个结果的?

    • 在第二种聚合物的情况下,它将是'b'而不是'a'。当然,如果选择了最终的聚合物,则翻转的定义如下 A[127]=2*A[126]+A[127] 需要注意的是,由于翻转,位置将改变为2、0或-2。 不管怎么说,现在我的问题是,平衡距离比应该的要高得多。理想情况下,我被告知它应该是0,或者最大可能是2和4。比这更大的可能性是微乎其微的。但我的代码经常给出22、30等值。谁能告诉我怎么了?请随时要求进一

    • 我使用preg_split正则表达式将句子拆分成数组。我能够成功地做到这一点。然而,我告诉preg_replace查找的模式的一部分是文本本身的一部分。所以部分文字也被删除了。有没有办法把模式重新插入数组?例如,如果我告诉preg_spit搜索一个句点和其后的一个大写字母,它将从数组中删除这个大写字母,这是我不想要的。 这是代码: 示例字符串: 这是第一句。这是第二句吗?这是第三句!这是第四句:这

    • QSplitter 实质上是一个窗口部件,但同时它可以包含一些其他窗口部件。在切分窗口(splitter)中的这些窗口部件会通过切分条(splitter handle)而分隔开来。用户可以 通过拖动这些切分条来改变切分窗口中子窗口部件的尺寸。切分窗口常常可以用作布局管理 器的替代,从而可以把更多的控制权交给用户。 11.5.1使用方法 大家知道,QSplitter 是一个容器类,Qt Design

    • 如果我想在Flink中分裂一个流,那么最好的方法是什么?