Я написал многопоточную программу с использованием Java fork/join framework в jre 1.7. Эта программа направлена на поиск определенных точек, которые удовлетворяют заданному условию во всех узлах Quadtree (каждый листовой узел в квадранте может быть заполнен неограниченным числом точек, например, может быть нулем или 1000). Я протестировал ускорение многопоточной программы по сравнению с последовательной программой на 16-ядерном процессоре, а ускорение - только 1,3-1,5. Ниже псевдокод:Java 7 Multithread Fork Join Scheduler
public class QuadtreeFindMultiThread extends RecursiveTask<IntArrayList> {
private Quadtree T;
private ObjectArrayList<Node> leaf_nodes;
private ObjectArrayList<Entry> candidatePoints;
private static int POINT_THRESHOLD = 50;
private static int NODE_THRESHOLD = 1;
public QuadtreeFindMultiThread(Quadtree T) {
this.T = T
this.leaf_nodes = T.get_nonempty_leaf_nodes();
this.candidatePoints = new IntArrayList();
}
private QuadtreeFindMultiThread(Quadtree T, IntArrayList leaf_nodes) {
this.T = T;
this.leaf_nodes = leaf_nodes; // reference copy
this.candidatePoints = new IntArrayList();
}
private IntArrayList QuadtreeFind() {
//...
//...
return candidatePoints;
}
private int getPointNum(){
int count = 0;
for(Node node:this.leaf_nodes){
count += node.getAllPoints().size();
}
return count;
}
@Override
public IntArrayList compute() {
if (this.getPointNum() <= POINT_THRESHOLD || this.leaf_nodes.size() <= NODE_THRESHOLD) {// trivial problem, solve by single thread
this.candidatePoints = QuadtreeFind();
} else {// START: divide and conquer
// Divide Step: partition this.leaf_nodes by direction: NW, NE, SW, SE
Partition leaf_nodes to four quadrants: leaf_nodes_NW,
leaf_nodes_NE,
leaf_nodes_SW,
leaf_nodes_SE
// Conquer Step
QuadtreeFindMultiThread thread_NW = new QuadtreeFindMultiThread(
this.T, leaf_nodes_NW);
QuadtreeFindMultiThread thread_NE = new QuadtreeFindMultiThread(
this.T, leaf_nodes_NE);
QuadtreeFindMultiThread thread_SW = new QuadtreeFindMultiThread(
this.T, leaf_nodes_SW);
QuadtreeJoinMultiThread thread_SE = new QuadtreeFindMultiThread(
this.T, leaf_nodes_SE);
// fork three new sub threads
thread_NE.fork();
thread_SW.fork();
thread_SE.fork();
this.candidatePoints.addAll(thread_NW.compute()); // main thread
this.candidatePoints.addAll(thread_NE.join());
this.candidatePoints.addAll(thread_SW.join());
this.candidatePoints.addAll(thread_SE.join());
}// END: divide and conquer
return this.candidatePoints;
}
}
Я новичок в Java многопоточного программирования, почему эта программа получила так плохо форсировки по процессорной машине 16-ядро? Я также тестировал эту многопоточную программу на своем ноутбуке с двумя ядрами и двумя виртуальными ядрами, ускорение также приближается к 1.3-1.5. Производительность многопоточной программы на моем ноутбуке даже лучше, чем у 16-процессорного процессора.
Похоже, что политика расписания по умолчанию fork/join framefork - это LIFO, как я могу изменить FIFO?
Кстати, я обнаружил, что обработка некоторых листовых узлов, у которых много точек, занимает много времени обработки. Могу ли я изменить планировщик fork/join таким образом, чтобы он сначала обрабатывал узлы с большим количеством точек? Таким образом, он должен получить лучшую производительность. Спасибо!
Больше узлов увеличивается накладные расходы. Вы хотите иметь как можно меньше узлов, которые будут использовать все процессоры. –
@PeterLawrey Так увеличить POINT_THRESHOLD и NODE_THRESHOLD, чтобы увеличить детализацию потоков? Но я думал, что плохая производительность может быть связана с грубой детализацией ... Если мы увеличим детализацию, тогда больше очков будет обработано этим потоком, время обработки потока будет суперлинейным до количества точек в листовых узлах. Таким образом, грубая гранулярность может увеличить время обработки. – Jinfeng
Если у вас 16 процессоров, вам потребуется не менее 16-64 потоков. –