Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java7多线程Fork-Join调度程序_Java_Multithreading - Fatal编程技术网

Java7多线程Fork-Join调度程序

Java7多线程Fork-Join调度程序,java,multithreading,Java,Multithreading,我在jre 1.7中使用Java fork/join框架编写了一个多线程程序。该程序的目的是在四叉树的所有节点中找到满足指定条件的某些点(四叉树中的每个叶节点可以用不受限制的点数填充,例如,可以是零或1000)。我在16核处理器机器上测试了多线程程序与串行程序的加速比,而加速比仅为1.3-1.5。下面是伪代码: public class QuadtreeFindMultiThread extends RecursiveTask<IntArrayList> { private Quad

我在jre 1.7中使用Java fork/join框架编写了一个多线程程序。该程序的目的是在四叉树的所有节点中找到满足指定条件的某些点(四叉树中的每个叶节点可以用不受限制的点数填充,例如,可以是零或1000)。我在16核处理器机器上测试了多线程程序与串行程序的加速比,而加速比仅为1.3-1.5。下面是伪代码:

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;
}


}
公共类QuadtreeFindMultiThread扩展递归任务{
私有四叉树T;
私有ObjectArrayList叶节点;
私有对象列表候选点;
私有静态int点_阈值=50;
私有静态int节点_阈值=1;
公共四叉树find多线程(四叉树T){
这个。T=T
this.leaf_nodes=T.get_nonempty_leaf_nodes();
this.candidatePoints=new IntArrayList();
}
私有QuadtreeFindMultiThread(四叉树T、IntArrayList叶节点){
T=T;
this.leaf\u nodes=leaf\u nodes;//引用副本
this.candidatePoints=new IntArrayList();
}
私有IntArrayList QuadtreeFind(){
//...
//...
返回候选分数;
}
私有int getPointNum(){
整数计数=0;
for(节点:this.leaf\u节点){
count+=node.getAllPoints().size();
}
返回计数;
}
@凌驾
公共IntArrayList compute(){

如果(this.getPointNum()任何并行问题的技巧都是平衡两个不同的问题:

一方面,我们希望通过使任务尽可能小来获得尽可能好的负载平衡,这样我们就不必在每个人都在等待时等待单个CPU完成其庞大的最后一个任务。另一方面,调度细粒度任务会增加开销,因此我们希望使任务尽可能大,以添加尽可能少的调度尽可能地降低开销

诀窍是在这两个极端之间找到一个很好的平衡,这就是为什么fork/join程序通常有一个阈值,从这个阈值开始,任务是单线程执行的。因此,正如Peter在他的评论中所观察到的那样,您需要调整两个阈值以获得最佳性能


最佳阈值取决于许多因素——主要是问题的大小,但不同的计算机体系结构、内存等也会对其产生很大影响。解决这一问题的最佳方法是将阈值作为一个输入参数,并以不同的程度运行基准测试。

没有太多关于此框架的文档。这当然是可行的这个框架是为平衡树的递归分解(DAG)设计的。它不能很好地容忍误用,因为它最初是作为一篇研究论文中的实验设计的

框架想要左、右、左、叉()右、计算()左、连接()。这样,它沿着平衡树的叶子走下去。分叉的任务回到它的状态,希望被其他线程窃取。当一切按计划进行时,每个线程为其他线程分叉足够的任务,并保持忙碌

您正在做的是将三个任务放回deque,然后处理一个quad。这并不能很好地分散工作。最终可能会出现多个线程有多个挂起的任务,而不是多个线程有几个挂起的任务。此框架无法正确地进行负载平衡

join()还有一个问题。join()需要一个上下文切换来释放线程以进行其他工作。此框架无法进行上下文切换,因此它会为每个join()创建一个“延续线程”,然后发出一个wait()对于连接线程。对于许多连接,您可能会有大量的创建/销毁开销。Java8版本取消了“延续线程”,但最终会频繁暂停(尤其是您执行的方式)


尝试重新设计以处理DAG,看看会发生什么。对于16个线程,它应该可以很好地工作。

更多的节点会增加开销。您希望使用尽可能少的节点来使用所有CPU。@PeterLawrey因此增加POINT_阈值和NODE_阈值以增加线程粒度?但我认为性能差可能是因为粒度较粗…如果我们增加粒度,那么该线程将处理更多的点,线程的处理时间与叶节点中的点的数量呈超线性关系。因此,粗粒度可能会增加处理时间。如果您有16个CPU,则至少需要16-64个线程。谢谢您的回答!嗨,edharned,谢谢您的回答。我有七个几个问题:1.如何实现多个具有许多挂起任务的线程?您能给出一个具体的代码示例吗?:)正如我所知,fork/join框架使用默认的后进先出调度策略,与FIFO调度策略相比,这大大减少了活动线程的数量;2.为什么在每个递归步骤中划分为三个子任务会导致不平衡树,而二进制划分会导致平衡树?就我而言,平衡与否应该取决于这里提到了DOC_THRESHOLD和NODE_THRESHOLD…许多问题。你需要生活在框架的边界内。它最初是一篇研究论文的实验,而不是一个商业应用程序开发包。线程必须醒来去寻找工作,所以没有办法平衡负载。在树中,你一半,fork/compute,w这使其他线程有机会拿起分叉任务并执行相同的操作。每个线程都在执行一个拆分到阈值的任务。这使其他线程有机会参与。有关更多详细信息,请查看源代码。