4 回答

TA貢獻1772條經(jīng)驗 獲得超8個贊
使用有一些缺點Arrays.parallelSort
它使用
ForkJoinPool.commonPool()
并且會與默認使用它的其他功能戰(zhàn)斗(例如parallel()
在流上)線程池
Arrays.parallelSort
的使用是不可配置的(只能通過增加公共池線程數(shù)量在全局級別上使用)它在小數(shù)據(jù)集上表現(xiàn)更差(數(shù)組通常包含很少的元素,JDK 甚至承認,例如,大多數(shù)元素
ArrayList
在其整個生命周期中都保持為空,這節(jié)省了相當多的內(nèi)存和 CPU 時間,因為不實例化永遠不會填充的數(shù)組)
另一個軼事場景:假設(shè)您實現(xiàn)了一些需要排序的紙牌游戲。將多個游戲并行執(zhí)行非常容易,而不是將一次運行的排序機制并行化,后者可能只占用整個游戲循環(huán)的一小部分。您現(xiàn)在失去了一種簡單的并行化方法(例如,在遺傳算法的上下文中運行游戲時)。
但是,是的,如果您碰巧有大型數(shù)組并且排序是應(yīng)用程序運行時的重要組成部分,請使用Arrays.parallelSort
.
編輯:如果給定的數(shù)組少于 4096 個元素,即使Arrays.parallelSort
切換到正常排序:這都是為了顯示意圖——如果可能的話,你想要一個并行排序,它與僅僅調(diào)用 . 具有不同的含義sort
。挑剔一點:它確實在小數(shù)組上表現(xiàn)更差,因為它必須額外檢查數(shù)組是否包含少于 4096 個元素,以及一些關(guān)于公共池線程數(shù)的其他檢查(開銷當然可以忽略不計):) .

TA貢獻1789條經(jīng)驗 獲得超10個贊
stream()這與何時使用vs 的問題沒有太大區(qū)別parallelStream()——這取決于您擁有多少數(shù)據(jù)。當然,大多數(shù)時間,當并行排序 10 個元素時,將被底層的線程框架(文檔未指定)消耗,而不是排序本身。
但是您也想知道為什么引入 IMO 此類方法。硬件正在(已經(jīng)移動?)轉(zhuǎn)向許多CPU,而不是更多GHz,因此對于任何希望在未來 20 年內(nèi)仍然存在的語言來說,并行處理只是一個正常過程。
至于你實際需要多少數(shù)據(jù)才能表現(xiàn)出性能,parallelSort再加上sort知道我們至少 MIN_ARRAY_SORT_GRAN + 1需要獲得任何潛在的好處;編寫一個適當?shù)臏y試來證明對于這個特定的設(shè)置和運行,你至少需要X數(shù)字,并不那么復雜。您還必須考慮到某些數(shù)組可能已經(jīng)排序(進一步解釋),而某些數(shù)組可能完全未排序(5,4,3,2,1例如),這會給第二個數(shù)組帶來一些懲罰。
獲取一些隨機數(shù)據(jù)并進行測試:
@Warmup(iterations = 10)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
public class ParallelSort {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(ParallelSort.class.getName())
.build();
new Runner(opt).run();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@Fork(1)
public int[] parallel(ParallelSortExecutionPlan plan) {
Arrays.parallelSort(plan.ints());
return plan.ints();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@Fork(1)
public int[] nonParallel(ParallelSortExecutionPlan plan) {
Arrays.sort(plan.ints());
return plan.ints();
}
}
@State(Scope.Benchmark)
public class ParallelSortExecutionPlan {
@Param(value = {"10", "100", "1000", "10000", "100000", "1000000"})
private int howMany;
private int[] ints;
public static void main(String[] args) {
}
@Setup(Level.Invocation)
public void setUp() {
ints = new int[howMany];
for (int i = 0; i < howMany; ++i) {
ints[i] = ThreadLocalRandom.current().nextInt();
}
}
int[] ints() {
return ints;
}
}
請注意第二個類正在使用@Setup(Level.Invocation)(如果你知道一點JMH)——這是一個非常鋒利的工具;Invocation但我使用它是因為我希望每個方法都有一個未排序的數(shù)組。否則,如果Trial將被使用例如 - 只有第一次調(diào)用將是一個未排序的數(shù)組,該@Benhcmark方法的所有其他調(diào)用都已經(jīng)排序。為了好玩,您可以將該單行更改為@Setup(Level.Trial)例如并查看結(jié)果,它們將毫無意義。
運行此顯示:
Benchmark (howMany) Mode Cnt Score Error Units
ParallelSort.nonParallel 10 avgt 2 128.847 ns/op
ParallelSort.parallel 10 avgt 2 116.656 ns/op
ParallelSort.nonParallel 100 avgt 2 1956.746 ns/op
ParallelSort.parallel 100 avgt 2 1963.335 ns/op
ParallelSort.nonParallel 1000 avgt 2 32162.611 ns/op
ParallelSort.parallel 1000 avgt 2 31716.915 ns/op
ParallelSort.nonParallel 10000 avgt 2 423531.663 ns/op
ParallelSort.parallel 10000 avgt 2 201802.609 ns/op
ParallelSort.nonParallel 100000 avgt 2 6503511.987 ns/op
ParallelSort.parallel 100000 avgt 2 1363169.661 ns/op
ParallelSort.nonParallel 1000000 avgt 2 69058738.586 ns/op
ParallelSort.parallel 1000000 avgt 2 13469112.930 ns/op
對我來說幾乎是一個非常期待的輸出。

TA貢獻1876條經(jīng)驗 獲得超6個贊
不,我會對足夠小的陣列說不。設(shè)置線程的開銷不會導致明顯的加速。
關(guān)鍵是“夠小”。它不會對所有問題都有相同的答案。
永遠不應(yīng)該應(yīng)用教條,除非是在這個教條規(guī)則的情況下。就像我們唯一不應(yīng)該容忍的是不寬容一樣。某處存在波普爾悖論。

TA貢獻1827條經(jīng)驗 獲得超4個贊
除了公共池使用和可優(yōu)化的最小大小等原因之外,如果您通常有許多事務(wù)需要并行進行排序,則您可能也不需要并行化單個排序。
在那種情況下,您可以通過拆分工作包來避免開銷。(然而,具有可配置并行工作的可控執(zhí)行器也適用于多線程提交——您只需增加停放線程和上下文切換的數(shù)量)
添加回答
舉報