4 回答

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

TA貢獻(xiàn)1789條經(jīng)驗(yàn) 獲得超10個(gè)贊
stream()這與何時(shí)使用vs 的問題沒有太大區(qū)別parallelStream()——這取決于您擁有多少數(shù)據(jù)。當(dāng)然,大多數(shù)時(shí)間,當(dāng)并行排序 10 個(gè)元素時(shí),將被底層的線程框架(文檔未指定)消耗,而不是排序本身。
但是您也想知道為什么引入 IMO 此類方法。硬件正在(已經(jīng)移動(dòng)?)轉(zhuǎn)向許多CPU,而不是更多GHz,因此對于任何希望在未來 20 年內(nèi)仍然存在的語言來說,并行處理只是一個(gè)正常過程。
至于你實(shí)際需要多少數(shù)據(jù)才能表現(xiàn)出性能,parallelSort再加上sort知道我們至少 MIN_ARRAY_SORT_GRAN + 1需要獲得任何潛在的好處;編寫一個(gè)適當(dāng)?shù)臏y試來證明對于這個(gè)特定的設(shè)置和運(yùn)行,你至少需要X數(shù)字,并不那么復(fù)雜。您還必須考慮到某些數(shù)組可能已經(jīng)排序(進(jìn)一步解釋),而某些數(shù)組可能完全未排序(5,4,3,2,1例如),這會給第二個(gè)數(shù)組帶來一些懲罰。
獲取一些隨機(jī)數(shù)據(jù)并進(jìn)行測試:
@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;
}
}
請注意第二個(gè)類正在使用@Setup(Level.Invocation)(如果你知道一點(diǎn)JMH)——這是一個(gè)非常鋒利的工具;Invocation但我使用它是因?yàn)槲蚁M總€(gè)方法都有一個(gè)未排序的數(shù)組。否則,如果Trial將被使用例如 - 只有第一次調(diào)用將是一個(gè)未排序的數(shù)組,該@Benhcmark方法的所有其他調(diào)用都已經(jīng)排序。為了好玩,您可以將該單行更改為@Setup(Level.Trial)例如并查看結(jié)果,它們將毫無意義。
運(yùn)行此顯示:
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
對我來說幾乎是一個(gè)非常期待的輸出。

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

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