2016-05-26 41 views
0

我試圖在很多線程上編寫生命遊戲,1個單元= 1個線程,它需要線程之間的同步,所以沒有線程會開始計算它在新線程沒有完成讀取之前的狀態之前的新狀態。這裏是我的代碼非常慢的同步

 public class Cell extends Processor{ 
      private static int count = 0; 
      private static Semaphore waitForAll = new Semaphore(0); 
      private static Semaphore waiter = new Semaphore(0); 
      private IntField isDead; 
      public Cell(int n) 
      { 
       super(n); 
       count ++; 
      } 
      public void initialize() 
      { 
       this.algorithmName = Cell.class.getSimpleName(); 
       isDead = new IntField(0); 
       this.addField(isDead, "state"); 
      } 
      public synchronized void step() 
      { 
       int size = neighbours.size(); 
       IntField[] states = new IntField[size]; 
       int readElementValue = 0; 
       IntField readElement; 
       sendAll(new IntField(isDead.getDist())); 
       Cell.waitForAll.release(); 
    //here wait untill all other threads finish reading 
        while (Cell.waitForAll.availablePermits() != Cell.count) { 
        } 
    //here release semaphore neader lower 
       Cell.waiter.release(); 
       for (int i = 0; i < neighbours.size(); i++) { 
        readElement = (IntField) reciveMessage(neighbours.get(i)); 
        states[i] = (IntField) reciveMessage(neighbours.get(i)); 
       } 
       int alive = 0; 
       int dead = 0; 
       for(IntField ii: states) 
       { 
        if(ii.getDist() == 1) 
         alive++; 
        else 
         dead++; 
       } 
       if(isDead.getDist() == 0) 
       { 
        if(alive == 3) 
         isDead.setValue(1); 
        else 
         ; 
       } 
       else 
       { 
        if(alive == 3 || alive == 2) 
         ; 
        else 
         isDead.setValue(0); 
       } 
       try { 
        while(Cell.waiter.availablePermits() != Cell.count) 
        { 
         ; 
         //if every thread finished reading we can acquire this semaphore 
        } 
        Cell.waitForAll.acquire(); 
        while(Cell.waitForAll.availablePermits() != 0) 
         ; 
//here we make sure every thread ends step in same moment 
        Cell.waiter.acquire(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 

處理器 類擴展thread和運行方法,如果我打開開關,它會調用step()方法。以及它對少量細胞的作用很好,但是當我運行ABOU 36細胞時,它開始非常緩慢,如何修復我的同步,使其更快?

+0

就像一個說明,多線程不是一個很好的方式來完成這種事情,除了個人實驗。正如您發現的那樣,由於線程開銷,性能可能會非常糟糕,而單線程解決方案可以更好地從舊板計算新狀態。 – hexafraction

+0

是的,這是爲了個人實驗,但只有36個線程,他們做的非常簡單的計算,這就是爲什麼我很驚訝,也許有,肯定有更好的同步方法,那麼我有兩個'信號燈' – whd

+0

如果每個單元有一個線程,那麼爲什麼實例方法Cell.step()需要同步?爲什麼多個線程需要在同一個'Cell'上爭用這個方法? –

回答

1

使用大量的線程往往不是非常有效,但36並不是很多,我期望它本身產生的差異,你會描述爲「非常慢」。我認爲這個問題更可能是你的戰略所固有的。特別是,我懷疑這個忙等待是有問題的:

Cell.waitForAll.release(); 
//here wait untill all other threads finish reading 
while (Cell.waitForAll.availablePermits() != Cell.count) { 
} 

忙等待是總是性能問題,因爲你是用一遍又一遍的測試條件下佔用CPU的。這種繁忙等待比大多數情況下更糟糕,因爲它涉及測試同步對象的狀態,這不僅會產生額外的開銷,還會在線程間引入額外的干擾。

而不是忙等待,你想使用各種方法之一,使線程暫停執行,直到條件滿足。看起來你實際上做的是創建一個窮人版的CyclicBarrier,所以你可以考慮改用CyclicBarrier本身。另外,由於這是一個學習練習,因此您可以從學習如何使用Object.wait(),Object.notify()Object.notifyAll() - Java的內置條件變量實現中受益。

如果你堅持使用信號量,那麼我認爲你可以不用忙碌等待。使用信號量的關鍵在於它能夠獲取指示線程可以繼續執行的信號量(完全),而不是可用許可證的數量。如果您維護一個單獨的變量,用於跟蹤給定點上給定信號量上有多少線程正在等待,則到達該點的每個線程都可以確定是否釋放所有其他線程(並自行繼續)或是否嘗試阻止獲取信號量。

+0

看起來好像有很多東西可以幫我學習,謝謝! – whd