2011-03-30 22 views
5

Dün, Java 7'de paralel matris çoğaltmasıyla ilgili bir soru soruldu: here çatal/birleştirme çerçevesi. Axtavt yardımıyla çalışmam için örnek programımı aldım. Şimdi sadece Java 6 işlevselliğini kullanan eşdeğer bir program uyguluyorum. Ben dün aynı sorunu alıyorum, akstavt'ın bana verdiği geri bildirimin uygulanmasına itiraz ediyorum (bence). Bir şey mi görüyorum? Kodu: Ben önerdi ve bu sorunu düzeltildi olarak ben eşitlenmiş eklenmesi çalıştıJava'da Paralel Matris Çarpımı 6

package algorithms; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.TimeUnit; 

public class Java6MatrixMultiply implements Algorithm { 

    private static final int SIZE = 1024; 
    private static final int THRESHOLD = 64; 
    private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); 

    private final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS); 

    private float[][] a = new float[SIZE][SIZE]; 
    private float[][] b = new float[SIZE][SIZE]; 
    private float[][] c = new float[SIZE][SIZE]; 

    @Override 
    public void initialize() { 
     init(a, b, SIZE); 
    } 

    @Override 
    public void execute() { 
     MatrixMultiplyTask task = new MatrixMultiplyTask(a, 0, 0, b, 0, 0, c, 0, 0, SIZE); 
     task.split(); 

     executor.shutdown();  
     try { 
      executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS); 
     } catch (InterruptedException e) { 
      System.out.println("Error: " + e.getMessage()); 
     } 
    } 

    @Override 
    public void printResult() { 
     check(c, SIZE); 

     for (int i = 0; i < SIZE && i <= 10; i++) { 
      for (int j = 0; j < SIZE && j <= 10; j++) {   
       if(j == 10) { 
        System.out.print("..."); 
       } 
       else { 
        System.out.print(c[i][j] + " "); 
       } 
      } 

      if(i == 10) { 
       System.out.println(); 
       for(int k = 0; k < 10; k++) System.out.print(" ... "); 
      } 

      System.out.println(); 
     }  

     System.out.println(); 
    } 

    // To simplify checking, fill with all 1's. Answer should be all n's. 
    static void init(float[][] a, float[][] b, int n) { 
     for (int i = 0; i < n; ++i) { 
      for (int j = 0; j < n; ++j) { 
       a[i][j] = 1.0F; 
       b[i][j] = 1.0F; 
      } 
     } 
    } 

    static void check(float[][] c, int n) { 
     for (int i = 0; i < n; i++) { 
      for (int j = 0; j < n; j++) { 
       if (c[i][j] != n) { 
        throw new Error("Check Failed at [" + i + "][" + j + "]: " + c[i][j]); 
        //System.out.println("Check Failed at [" + i + "][" + j + "]: " + c[i][j]); 
       } 
      } 
     }  
    } 

    public class Seq implements Runnable { 

     private final MatrixMultiplyTask a; 
     private final MatrixMultiplyTask b; 

     public Seq(MatrixMultiplyTask a, MatrixMultiplyTask b, int size) { 
      this.a = a; 
      this.b = b; 

      if (size <= THRESHOLD) { 
       executor.submit(this); 
      } else {    
       a.split(); 
       b.split(); 
      } 
     } 

     public void run() { 
      a.multiplyStride2(); 
      b.multiplyStride2(); 
     } 
    } 

    private class MatrixMultiplyTask { 
     private final float[][] A; // Matrix A 
     private final int aRow; // first row of current quadrant of A 
     private final int aCol; // first column of current quadrant of A 

     private final float[][] B; // Similarly for B 
     private final int bRow; 
     private final int bCol; 

     private final float[][] C; // Similarly for result matrix C 
     private final int cRow; 
     private final int cCol; 

     private final int size; 

     MatrixMultiplyTask(float[][] A, int aRow, int aCol, float[][] B, 
       int bRow, int bCol, float[][] C, int cRow, int cCol, int size) { 

      this.A = A; 
      this.aRow = aRow; 
      this.aCol = aCol; 
      this.B = B; 
      this.bRow = bRow; 
      this.bCol = bCol; 
      this.C = C; 
      this.cRow = cRow; 
      this.cCol = cCol; 
      this.size = size; 
     } 

     public void split() { 
      int h = size/2; 

      new Seq(new MatrixMultiplyTask(A, 
        aRow, aCol, // A11 
        B, bRow, bCol, // B11 
        C, cRow, cCol, // C11 
        h), 

      new MatrixMultiplyTask(A, aRow, aCol + h, // A12 
        B, bRow + h, bCol, // B21 
        C, cRow, cCol, // C11 
        h), h); 

      new Seq(new MatrixMultiplyTask(A, 
        aRow, aCol, // A11 
        B, bRow, bCol + h, // B12 
        C, cRow, cCol + h, // C12 
        h), 

      new MatrixMultiplyTask(A, aRow, aCol + h, // A12 
        B, bRow + h, bCol + h, // B22 
        C, cRow, cCol + h, // C12 
        h), h); 

      new Seq(new MatrixMultiplyTask(A, aRow 
        + h, aCol, // A21 
        B, bRow, bCol, // B11 
        C, cRow + h, cCol, // C21 
        h), 

      new MatrixMultiplyTask(A, aRow + h, aCol + h, // A22 
        B, bRow + h, bCol, // B21 
        C, cRow + h, cCol, // C21 
        h), h); 

      new Seq(new MatrixMultiplyTask(A, aRow 
        + h, aCol, // A21 
        B, bRow, bCol + h, // B12 
        C, cRow + h, cCol + h, // C22 
        h), 

      new MatrixMultiplyTask(A, aRow + h, aCol + h, // A22 
        B, bRow + h, bCol + h, // B22 
        C, cRow + h, cCol + h, // C22 
        h), h); 
     } 

     public void multiplyStride2() { 
      for (int j = 0; j < size; j += 2) { 
       for (int i = 0; i < size; i += 2) { 

        float[] a0 = A[aRow + i]; 
        float[] a1 = A[aRow + i + 1]; 

        float s00 = 0.0F; 
        float s01 = 0.0F; 
        float s10 = 0.0F; 
        float s11 = 0.0F; 

        for (int k = 0; k < size; k += 2) { 

         float[] b0 = B[bRow + k]; 

         s00 += a0[aCol + k] * b0[bCol + j]; 
         s10 += a1[aCol + k] * b0[bCol + j]; 
         s01 += a0[aCol + k] * b0[bCol + j + 1]; 
         s11 += a1[aCol + k] * b0[bCol + j + 1]; 

         float[] b1 = B[bRow + k + 1]; 

         s00 += a0[aCol + k + 1] * b1[bCol + j]; 
         s10 += a1[aCol + k + 1] * b1[bCol + j]; 
         s01 += a0[aCol + k + 1] * b1[bCol + j + 1]; 
         s11 += a1[aCol + k + 1] * b1[bCol + j + 1]; 
        } 

        C[cRow + i][cCol + j] += s00; 
        C[cRow + i][cCol + j + 1] += s01; 
        C[cRow + i + 1][cCol + j] += s10; 
        C[cRow + i + 1][cCol + j + 1] += s11; 
       } 
      }   
     } 
    } 
} 

cevap

1

Bu this sorusunu okuduktan sonra programımı uyarlamaya karar verdim. Yeni programım senkronizasyon olmadan çok iyi çalışıyor. Düşüncelerin için teşekkürler Peter.

Yeni kod: Öneriler için

package algorithms; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.FutureTask; 

public class Java6MatrixMultiply implements Algorithm { 

    private static final int SIZE = 2048; 
    private static final int THRESHOLD = 64; 
    private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); 

    private final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS); 

    private float[][] a = new float[SIZE][SIZE]; 
    private float[][] b = new float[SIZE][SIZE]; 
    private float[][] c = new float[SIZE][SIZE]; 

    @Override 
    public void initialize() { 
     init(a, b, SIZE); 
    } 

    @Override 
    public void execute() { 
     MatrixMultiplyTask mainTask = new MatrixMultiplyTask(a, 0, 0, b, 0, 0, c, 0, 0, SIZE); 
     Future future = executor.submit(mainTask); 

     try { 
      future.get(); 
     } catch (Exception e) { 
      System.out.println("Error: " + e.getMessage()); 
     } 
    } 

    @Override 
    public void printResult() { 
     check(c, SIZE); 

     for (int i = 0; i < SIZE && i <= 10; i++) { 
      for (int j = 0; j < SIZE && j <= 10; j++) {   
       if(j == 10) { 
        System.out.print("..."); 
       } 
       else { 
        System.out.print(c[i][j] + " "); 
       } 
      } 

      if(i == 10) { 
       System.out.println(); 
       for(int k = 0; k < 10; k++) System.out.print(" ... "); 
      } 

      System.out.println(); 
     }  

     System.out.println(); 
    } 

    // To simplify checking, fill with all 1's. Answer should be all n's. 
    static void init(float[][] a, float[][] b, int n) { 
     for (int i = 0; i < n; ++i) { 
      for (int j = 0; j < n; ++j) { 
       a[i][j] = 1.0F; 
       b[i][j] = 1.0F; 
      } 
     } 
    } 

    static void check(float[][] c, int n) { 
     for (int i = 0; i < n; i++) { 
      for (int j = 0; j < n; j++) { 
       if (c[i][j] != n) { 
        throw new Error("Check Failed at [" + i + "][" + j + "]: " + c[i][j]); 
        //System.out.println("Check Failed at [" + i + "][" + j + "]: " + c[i][j]); 
       } 
      } 
     }  
    } 

    public class Seq implements Runnable { 

     private final MatrixMultiplyTask a; 
     private final MatrixMultiplyTask b; 

     public Seq(MatrixMultiplyTask a, MatrixMultiplyTask b) { 
      this.a = a; 
      this.b = b;  
     } 

     public void run() { 
      a.run(); 
      b.run(); 
     } 
    } 

    private class MatrixMultiplyTask implements Runnable { 
     private final float[][] A; // Matrix A 
     private final int aRow; // first row of current quadrant of A 
     private final int aCol; // first column of current quadrant of A 

     private final float[][] B; // Similarly for B 
     private final int bRow; 
     private final int bCol; 

     private final float[][] C; // Similarly for result matrix C 
     private final int cRow; 
     private final int cCol; 

     private final int size; 

     public MatrixMultiplyTask(float[][] A, int aRow, int aCol, float[][] B, 
       int bRow, int bCol, float[][] C, int cRow, int cCol, int size) { 

      this.A = A; 
      this.aRow = aRow; 
      this.aCol = aCol; 
      this.B = B; 
      this.bRow = bRow; 
      this.bCol = bCol; 
      this.C = C; 
      this.cRow = cRow; 
      this.cCol = cCol; 
      this.size = size; 
     } 

     public void run() { 

      //System.out.println("Thread: " + Thread.currentThread().getName()); 

      if (size <= THRESHOLD) { 
       multiplyStride2(); 
      } else { 

       int h = size/2; 

         Seq seq1 = new Seq(new MatrixMultiplyTask(A, 
           aRow, aCol, // A11 
           B, bRow, bCol, // B11 
           C, cRow, cCol, // C11 
           h), 

         new MatrixMultiplyTask(A, aRow, aCol + h, // A12 
           B, bRow + h, bCol, // B21 
           C, cRow, cCol, // C11 
           h)); 

         Seq seq2 = new Seq(new MatrixMultiplyTask(A, 
           aRow, aCol, // A11 
           B, bRow, bCol + h, // B12 
           C, cRow, cCol + h, // C12 
           h), 

         new MatrixMultiplyTask(A, aRow, aCol + h, // A12 
           B, bRow + h, bCol + h, // B22 
           C, cRow, cCol + h, // C12 
           h)); 

         Seq seq3 = new Seq(new MatrixMultiplyTask(A, aRow 
           + h, aCol, // A21 
           B, bRow, bCol, // B11 
           C, cRow + h, cCol, // C21 
           h), 

         new MatrixMultiplyTask(A, aRow + h, aCol + h, // A22 
           B, bRow + h, bCol, // B21 
           C, cRow + h, cCol, // C21 
           h)); 

         Seq seq4 = new Seq(new MatrixMultiplyTask(A, aRow 
           + h, aCol, // A21 
           B, bRow, bCol + h, // B12 
           C, cRow + h, cCol + h, // C22 
           h), 

         new MatrixMultiplyTask(A, aRow + h, aCol + h, // A22 
           B, bRow + h, bCol + h, // B22 
           C, cRow + h, cCol + h, // C22 
           h));    



       final FutureTask s1Task = new FutureTask(seq2, null); 
       final FutureTask s2Task = new FutureTask(seq3, null); 
       final FutureTask s3Task = new FutureTask(seq4, null); 

       executor.execute(s1Task); 
       executor.execute(s2Task); 
       executor.execute(s3Task); 

       seq1.run(); 
       s1Task.run(); 
       s2Task.run(); 
       s3Task.run(); 

       try { 
        s1Task.get(); 
        s2Task.get(); 
        s3Task.get(); 
       } catch (Exception e) { 
        System.out.println("Error: " + e.getMessage()); 
        executor.shutdownNow(); 
       }  
      }  
     }  

     public void multiplyStride2() { 
      for (int j = 0; j < size; j += 2) { 
       for (int i = 0; i < size; i += 2) { 

        float[] a0 = A[aRow + i]; 
        float[] a1 = A[aRow + i + 1]; 

        float s00 = 0.0F; 
        float s01 = 0.0F; 
        float s10 = 0.0F; 
        float s11 = 0.0F; 

        for (int k = 0; k < size; k += 2) { 

         float[] b0 = B[bRow + k]; 

         s00 += a0[aCol + k] * b0[bCol + j]; 
         s10 += a1[aCol + k] * b0[bCol + j]; 
         s01 += a0[aCol + k] * b0[bCol + j + 1]; 
         s11 += a1[aCol + k] * b0[bCol + j + 1]; 

         float[] b1 = B[bRow + k + 1]; 

         s00 += a0[aCol + k + 1] * b1[bCol + j]; 
         s10 += a1[aCol + k + 1] * b1[bCol + j]; 
         s01 += a0[aCol + k + 1] * b1[bCol + j + 1]; 
         s11 += a1[aCol + k + 1] * b1[bCol + j + 1]; 
        } 

        C[cRow + i][cCol + j] += s00; 
        C[cRow + i][cCol + j + 1] += s01; 
        C[cRow + i + 1][cCol + j] += s10; 
        C[cRow + i + 1][cCol + j + 1] += s11; 
       } 
      }   
     } 
    } 
} 
3

. ;)

her satır 299 ms senkronize
  • çalıştı.
  • Döngüleri mutliplyStride olarak değiştirin, böylece satır yerine sütunla gider. 253 ms
  • her iki güncellemeler için bir satır kilitli yani (satır her çifti için bir kilit üstlendi. 216 ms
  • devre dışı bırakma parçacıkları için işlemci sayısı 2x -XX:-UseBiasedLocking 207 ms
  • kullanım kilitleme kanalı içerir. 199 ms.
  • double yerine 237 float ait ms kullanarak dışında aynı.
  • hiç senkronizasyonu. 174 ms.

beşinci seçenek yok Synchr az% 10'dan daha yavaştır görebileceğiniz gibi onization. Daha fazla kazanç istiyorsanız, daha önbellek dostu hale getirmek için verilere erişme şeklini değiştirmenizi öneriyorum. Ortalamanın kez 172 ms damla 2x2 instaed 2x4 blok hesaplamak Özetle

I İlginçtir

private final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS*2); 

public void multiplyStride2() { 
    for (int i = 0; i < size; i += 2) { 
     for (int j = 0; j < size; j += 2) { 

     // code as is...... 

      synchronized (C[cRow + i]) { 
       C[cRow + i][cCol + j] += s00; 
       C[cRow + i][cCol + j + 1] += s01; 

       C[cRow + i + 1][cCol + j] += s10; 
       C[cRow + i + 1][cCol + j + 1] += s11; 
      } 

göstermektedir. (senkronizasyon olmadan önceki sonuca göre daha hızlı);)

+0

Tanklar. Araştırmam için en iyi seçenek, java 7 örneğimle en çok ortak olan seçeneğidir. Bu yüzden multiplyStride yöntemini değiştirmekten kaçınmak istiyorum. Bence en iyi şey, Seq sınıfını değiştirmek veya hata ayıklamaktır, böylece aynı sıradaki subtasklar doğru sırada gerçekleştirilir. – TheArchitect