[英]Why adding cores slows down my java program after around 10 cores?
我的程序使用fork / join,如下所示運行數千個任務:
private static class Generator extends RecursiveTask<Long> {
final MyHelper mol;
final static SatChecker satCheck = new SatChecker();
public Generator(final MyHelper mol) {
super();
this.mol = mol;
}
@Override
protected Long compute() {
long count = 0;
try {
if (mol.isComplete(satCheck)) {
count = 1;
}
ArrayList<MyHelper> molList = mol.extend();
List<Generator> tasks = new ArrayList<>();
for (final MyHelper child : molList) {
tasks.add(new Generator(child));
}
for(final Generator task : invokeAll(tasks)) {
count += task.join();
}
} catch (Exception e){
e.printStackTrace();
}
return count;
}
}
我的程序大量使用isComplete和擴展方法的第三方庫。 extend方法也使用本機庫。 就MyHelper類而言,任務之間沒有共享變量或同步。
我使用linux中的taskset命令來限制我的應用程序使用的核心數。 我通過使用大約10個核心(比如大約60秒)獲得最佳速度。 這意味着使用10個以上的內核會導致應用程序變慢,因此16個內核可以同時完成6個內核(大約90秒)。
我更困惑,因為所選內核100%忙碌(除了垃圾收集之外)。 有誰知道什么會導致這么慢? 我應該在哪里解決這個問題?
PS:我在Scala / akka中也使用了ThreadPoolExecutor,但結果相似(雖然比fork / join慢)
PPS:我的猜測是,在MyHelper或SatCheck深處,有人穿過內存屏障(中毒緩存)。 但是我怎樣才能找到並修復或去做呢?
由於將線程/任務分配給不同的核心,可能會出現過載。 此外,您確定您的程序完全可並行化嗎? 實際上,某些程序不能總是100%有效地使用所有可用的cpu,並且分配任務所花費的時間可能會使程序減慢而不是幫助它。
我認為您應該使用molList
(或mol
)變量大小的閾值來避免分析太小的數據集。
我一直在玩fork / join只是為了理解框架,我的第一個例子沒有考慮到閾值。 顯然我的表現非常糟糕。 確定問題大小的適當限制就可以了。
找到正確的閾值值需要您花一點時間嘗試不同的值,看看性能如何變化。
所以,在這樣的compute
方法的最開頭加一個if
:
@Override
protected Long compute() {
if (mol.getSize() < THRESHOLD) //getSize or whatever gives you size of problem
return noForkJoinCompute(mol); //noForkJoinCompute gives you count without FJ
long count = 0;
try {
if (mol.isComplete(satCheck)) {
count = 1;
}
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.