簡體   English   中英

Stream.sorted()。limit()的性能

[英]performance of Stream.sorted().limit()

Java Streams同時運行sortedlimit方法,它們分別返回流的排序版本並返回一個流,只返回指定數量的流項。 當這些操作連續應用時,例如:

stream.sorted().limit(qty).collect(Collectors.toList())

排序是以對qty項進行排序還是整個列表排序的方式執行的? 換句話說,如果qty是固定的,那么這個操作是否在O(n) 文檔沒有單獨指定這些方法的性能或相互結合使用。

我問的原因是這些操作的明顯命令性實現是排序然后限制,取時間Θ(n * log(n)) 但是這些操作可以在O(n * log(qty)) ,智能流式框架可以在執行之前查看整個流以優化此特殊情況。

讓我首先指出Java語言規范對如何實現流的限制很少。 因此,詢問Java流的性能真的沒有太大意義:它們在實現之間會有很大差異。

另請注意, Stream是一個界面。 您可以創建自己的類來實現Stream以便根據需要對sorted執行任何性能或特殊行為。 因此,即使在一個實現的上下文中,真正詢問Stream的性能也沒有意義。 OpenJDK實現有許多實現Stream接口的類。

話雖如此,如果我們看一下OpenJDK實現, SortedOps的排序最終會在SortedOps類中進行(參見這里的源代碼),你會發現排序方法最終會返回有狀態操作的擴展。 例如:

private static final class OfInt extends IntPipeline.StatefulOp<Integer>

這些方法檢查上游是否已經排序,在哪種情況下它們只是將它傳遞給下游。 它們對於大小的流(即上游)也有特殊的例外情況,它們預先分配它們最終排序的數組,這將提高效率(通過它們用於未知大小流的SpinedBuffer )。 但是,只要上游尚未排序,它們就接受所有項目,然后對它們進行排序,然后發送到下游實例的accept方法。

因此得出的結論是,OpenJDK sorted實現收集所有項目,然后排序,然后發送到下游。 在某些情況下,當下游將丟棄某些元素時,這將浪費資源。 對於特殊情況,您可以自由地實現自己的專用排序操作,該操作比此更有效。 可能最直接的方法是實現一個Collector ,它保存流中n個最大或最小項的列表。 您的操作可能看起來像:

.collect(new CollectNthLargest(4)).stream()

取代

.sorted().limit(4)

我的StreamEx庫中有一個特殊的收集器,它執行此操作: MoreCollectors.least MoreCollectors.least(qty)

List<?> result = stream.collect(MoreCollectors.least(qty));

它在內部使用 PriorityQueue,並且在未排序的輸入上使用小數量時實際上工作得更快。 但是請注意,如果輸入主要是排序的,那么sorted().limit(qty)可能會更快,因為TimSort對於預分類數據來說速度非常快。

這取決於實現,也可能取決於流管道是否可以“看穿” sorted()limit()之間的潛在操作。

即使您要詢問OpenJDK實現,它也可能會發生變化,因為javadocs不保證運行時行為。 但不,目前它沒有實現k-min選擇算法。

您還必須記住, sorted()不適用於無限流,除非它們已經具有SORTED特性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM