无向图的DFS并行实现

时间:2013-06-04 20:54:54

标签: java multithreading performance algorithm parallel-processing

我一直在尝试用Java实现并行深度优先搜索,以获得无向图。我写了这段代码,但它无法正常工作。它没有加速。

主要方法:

 package dfsearch_v2;

 import java.util.Calendar;
 import java.util.Stack;
 import java.util.Random;

 public class DFSearch_v2 {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {

    long ts_b, ts_e;
    int el_count=100;
    int thread_count = 4;
    int vertices[][]; // graph matrix
    boolean isVisited[] = new boolean[el_count];
    for(int i=0;i<el_count;i++){
        for(int j=0;j<el_count;j++){
            Random boolNumber = new Random();
            boolean edge = boolNumber.nextBoolean(); 
            vertices[i][j]=edge ? 1 : 
        }   
    }


    DFSTest r[] = new DFSTest[thread_count];
    ts_b = Calendar.getInstance().getTimeInMillis();
    for(int i = 0; i < thread_count; i++) {
        r[i] = new DFSTest(el_count,vertices,isVisited);
        r[i].start();
    }

    for(int i = 0; i < thread_count;    
        try {   
            r[i].join();
          } catch (InterruptedException e) {

          }
    }
    ts_e = Calendar.getInstance().getTimeInMillis();
    System.out.println("Time "+(ts_e-ts_b));      
}

线程实现:

package dfsearch_v2;

import java.util.Stack;

public class DFSTest extends Thread {

    int numberOfNodes;
    int adj[][];
    boolean isVisit[];



public DFSTest(int numberOfNodes, int adj[][],boolean isVisit[]){
    this.numberOfNodes = numberOfNodes;
    this.adj=adj;  
    this.isVisit=isVisit;
}

public void run()
{
    int k,i,s=0;
    Stack<Integer> st = new Stack<>();
    for(k=0; k < numberOfNodes; k++) isVisit[k]=false;
    for (k = numberOfNodes - 1; k >= 0; k--) {
        st.push(k);
    }
        DFSearch(st, isVisit);


}

   private void DFSearch(Stack<Integer> st,boolean isVisit[]){
       synchronized(isVisit){
        int i,k;
        while (!st.empty()) { 
        k=st.pop();
        if (!isVisit[k]) {
            isVisit[k] = true;
            System.out.println("Node "+k+" is visit");

            for(i=numberOfNodes-1; i>=0; i--)
                if(adj[k][i]==1) st.push(i);
        }

    }

  }

 }


}

有人可以帮助我吗?我对并行编程很陌生。

由于

3 个答案:

答案 0 :(得分:1)

如果我正确理解你的程序,你就锁定了所有线程之间共享的isVisit数组 - 这意味着你不会获得任何加速,因为只有一个线程能够取得进展。请尝试使用ConcurrentHashMapConcurrentSkipListMap

// shared between all threads
ConcurrentMap<Integer, Boolean> map = new ConcurrentHashMap<>();

public boolean isVisit(Integer integer) {
    return map.putIfAbsent(integer, Boolean.TRUE) != null;
}

private void DFSearch(Stack<Integer> st) {
    if(!isVisit(st.pop())) {
       ...
    }
}

并发映射使用分片来增加并行性。使用putIfAbsent中的isVisit方法来避免数据争用(您只希望方法为一个线程返回false)。

至于如何在多个线程之间划分工作,请使用ConcurrentLinkedQueue工作线程。当一个线程没有更多的工作要执行时,它会将自己添加到工作线程队列中。当一个线程有两个要遍历的边时,它polls一个可用工作线程的工作线程队列,如果有一个可用,它会将一个边缘分配给工作线程。当所有线程都在可用的线程队列上时,您就遍历了整个列表。

答案 1 :(得分:1)

您不需要在 isVisit 上进行同步,这正在破坏您的并行性。布尔数组的多个读者/多个写入者应该是非常安全的。

如果可能的话,你应该避免线程之间的依赖关系。为此,请不要使用共享堆栈(如果这是您的代码正在执行的操作 - 目前还不清楚)。

在您的情况下,每个顶点完成的工作量很小,因此在每个线程中批处理工作是有意义的,并且只有在达到某个积压阈值时才考虑将工作交给其他线程。

答案 2 :(得分:0)

我改变了一点方法。现在它使用一个全局堆栈,由所有线程和n个本地堆栈共享,其中n是线程数。每个线程将其子树的节点存储在其本地堆栈中。最初,全局堆栈包含树的根,只有一个线程可以访问它,而其他线程正在等待工作线程唤醒。工作线程从全局堆栈检索并处理根,向其本地堆栈添加一个后继,然后将其余的后继(如果存在)推送到全局堆栈以由其他线程处理并唤醒所有等待的线程。所有其他线程遵循相同的方法(即当线程从全局堆栈获取一个节点时,它们将一个后继推送到它们的本地堆栈,然后将其余的推送到全局堆栈,然后开始访问它们的本地堆栈,直到它变空。)

然而,它并没有加速。我会感谢你们所有的进一步想法。

主要方法:

package dfsearch_v2;

import java.util.Calendar;
import java.util.Random;




public class DFSearch_v2 {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    // TODO code application logic here
    long ts_b, ts_e;
    //number of nodes
    int el_count=400;
int thread_count = 8;
    int gCounter=0;
    int vertices[][] = new int[el_count][el_count]; // graph matrix
    boolean isVisited[] = new boolean[el_count];

    for(int i=0;i<el_count;i++){
        for(int j=0;j<el_count;j++){
            Random boolNumber = new Random();
            boolean edge = boolNumber.nextBoolean(); 
            vertices[i][j]=edge ? 1 : 0;

        }   
    }
    DFSearch2 r[] = new DFSearch2[thread_count];
          ts_b = Calendar.getInstance().getTimeInMillis();
          for(int i = 0; i < thread_count; i++) {


            r[i] = new DFSearch2(el_count,vertices,isVisited,gCounter);
            r[i].start();

    }      
        for(int i = 0; i < thread_count; i++) {

        try {

            r[i].join();

        } catch (InterruptedException e) {

        }

    }
         ts_e = Calendar.getInstance().getTimeInMillis();
        System.out.println("Time "+(ts_e-ts_b));              
}    
}

线程实现:

package dfsearch_v2;

import java.util.Stack;



public class DFSearch2 extends Thread{

private boolean isVisit[];
private final Stack<Integer> globalStack;
int numberOfNodes;
//traversal is done ?
boolean isDone;
int adj[][];
// count visited nodes
int gCounter;

public DFSearch2(int number_Nodes,int adj[][],boolean isVisit[],int gCounter){
    this.numberOfNodes=number_Nodes;
    this.isVisit = isVisit;
    this.globalStack = new Stack<>();
    this.isDone=false;
    this.adj=adj;
    this.gCounter=gCounter;
    this.globalStack.push(number_Nodes-1);

}

public void run(){

        // local stack
        Stack<Integer> localStack = new Stack<>();
        while (!isDone) { 
            int k;
            synchronized(globalStack){
             k = globalStack.pop();  
             //pop until k is not visited
             while (isVisit[k]) { 
                if(globalStack.empty()) {
                    isDone=true;
                    return;
                }else{
                    k=globalStack.pop();
                }
              }

            } 
            // traverse sub-graph with start node k
            DFSearchNode(localStack,k);
            yield();
            if(globalStack.empty()) {
               isDone = true; 
            }
            // if gCounter is not null unvisited node are pushed in globalStack
            if(isDone&&gCounter<numberOfNodes){ 
                isDone=false;
                //unvisited nodes are pushed in globalStack
                for (int i = 0; i < isVisit.length; i++) {
                    if (!isVisit[i]) {
                      globalStack.push(i);  
                    }  

                }
            }


   }


}    
 synchronized private void DFSearchNode(Stack<Integer> localStack, int k){

            localStack.push(k);

            while (!localStack.empty()) {
               int s=localStack.pop();
               if (!isVisit[s]) {
                    isVisit[s] = true;
                    gCounter++;
                    //System.out.println("Node "+s+" is visit");
                   //first element is pushed into localStack and anothers in   globalStack
                     boolean flag = true; // local or global stack (true -> local; false ->global )
                     for(int i=numberOfNodes-1; i>=0; i--)
                     {
                       //   
                       if(i==s) continue;
                       //push another successors in global stack
                       if(adj[s][i]==1&&!flag&&!isVisit[s]){//visited nodes are not pushed in globalStack
                           globalStack.push(i);
                       }
                       //push first successor  in global stack
                       if(adj[s][i]==1&&flag&&!isVisit[s]) //visited nodes are not pushed in localStack
                       {
                           localStack.push(i);
                           flag=false; //only first element is pushed into localStack
                       } 

                     }                
               }


            }

}

}