2014-10-05 58 views
1

爲了並行,加快計算我「已經分裂一個長週期使用TPL兩個短的週期,這部分被稱爲PointGenerator和PointGenerator2在我的課波紋管:來拆分循環使用TPL

class CalcPiTPL 
    { 
     int n; 
     int totalCounter; 
     int counter1; 
     int counter2; 
     double aPi; 
     public StringBuilder Msg; // diagonstic message 
     Stopwatch stopWatch = new Stopwatch(); 

     public void Init(int aN) 
     { 
      stopWatch.Start(); 
      n = aN; // save total calculate-iterations amount 
      aPi = -1; // flag, if no any calculate-iteration has been completed 
      Msg = new StringBuilder("No any calculate-iteration has been completed"); 
     } 
     public void Run() 
     { 
      if (n < 1) 
      { 
       Msg = new StringBuilder("Invalid N-value"); 
       return; 
      } 

      Task[] tasks = new Task[2]; 
      tasks[0] = Task.Factory.StartNew((obj) => { PointGenerator((int)obj); }, n); 
      tasks[1] = Task.Factory.StartNew((obj) => { PointGenerator2((int)obj); }, n); 

      Task.WaitAll(tasks[0], tasks[1]); 
      totalCounter = counter1 + counter2; 
      aPi = 4.0 * ((double)totalCounter/(double)n); // to calculate approximate Pi - value 
      Console.WriteLine(aPi); 
      stopWatch.Stop(); 
      TimeSpan ts = stopWatch.Elapsed; 
      string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
      ts.Hours, ts.Minutes, ts.Seconds, 
      ts.Milliseconds/10); 
      Console.WriteLine("RunTime " + elapsedTime); 
     } 
     public double Done() 
     { 
      if (aPi > 0) 
      { 
       Msg = new StringBuilder("Calculates has been completed successful"); 
       return aPi; // return gotten value 
      } 
      else 
      { 
       return 0; // no result 
      } 
     } 
     public void PointGenerator(int n)//FIRST PART OF ONE BIG FOR-CYCLE 
     { 
      double s = 0.125; 
      double sP = s/(n/2); 
      double x = Math.Sqrt(sP); 
      for (double cX = 0; cX <= 0.25; cX += x) 
      { 
       for (double cY = 0; cY <= 0.5; cY += x) 
       { 
        if (((cX - 0.5) * (cX - 0.5) + (cY - 0.5) * (cY - 0.5)) < 0.25) 
        { 
         counter1++; // coordinate in a circle! mark it by incrementing N_0 
        } 
       } 
      } 
     } 

     public void PointGenerator2(int n)//SECOND PART OF ONE BIG FOR-CYCLE 
     { 
      double s = 0.125; 
      double sP = s/(n/2); 
      double x = Math.Sqrt(sP); 
      for (double cX = 0.25; cX <= 0.5; cX += x) 
      { 
       for (double cY = 0; cY <= 0.5; cY += x) 
       { 
        if (((cX - 0.5) * (cX - 0.5) + (cY - 0.5) * (cY - 0.5)) < 0.25) 
        { 
         counter2++; // coordinate in a circle! mark it by incrementing N_0 
        } 
       } 
      } 
     } 
    } 

這是不使用(TPL)任務相同的類,它有一個很長的週期。

class TCalcPi//unparallel calculating method 
    { 
     int N; 
     int n_0; 
     double aPi; 
     public StringBuilder Msg; // diagnostic message 


     Stopwatch stopWatch = new Stopwatch(); 

     public void Init(int aN) 
     { 
      stopWatch.Start(); 
      N = aN; // save total calculate-iterations amount 
      aPi = -1; // flag, if no any calculate-iteration has been completed 
      Msg = new StringBuilder("No any calculate-iteration has been completed"); 
     } 

     public void Run() 
     { 
      if (N < 1) 
      { 
       Msg = new StringBuilder("Invalid N - value"); 
       return; 
      } 

      double s = 0.25; 
      double sP = s/N; 
      double x = Math.Sqrt(sP); 
      for (double cX = 0; cX <= 0.5; cX += x)//ONE LONG FOR-CYCLE 
      { 
       for(double cY = 0; cY <= 0.5; cY += x) 
       { 
        if (((cX - 0.5) * (cX - 0.5) + (cY - 0.5) * (cY - 0.5)) < 0.25) 
        { 
         n_0++; // coordinate in a circle! mark it by incrementing N_0 
        } 
       } 
      } 
      aPi = 4.0 * ((double)n_0/(double)N); // to calculate approximate Pi - value 
      stopWatch.Stop(); 
      TimeSpan ts = stopWatch.Elapsed; 
      string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
      ts.Hours, ts.Minutes, ts.Seconds, 
      ts.Milliseconds/10); 
      Console.WriteLine("RunTime " + elapsedTime); 
     } 
     public double Done() 
     { 
      if (aPi > 0) 
      { 
       Msg = new StringBuilder("Calculates has been completed successful"); 
       return aPi; // return gotten value 
      } 
      else 
      { 
       return 0; // no result 
      } 
     } 
    } 

但並行化一流的工作速度更快,比並行(使用TPL)類如何解決它呢?

+1

嘗試Parallel.For。 Parallel.For中的邏輯決定了應該創建多少個任務,並考慮了內核的數量。它可能會給你更好的/有趣的結果。 – 2014-10-05 19:51:02

+0

@ErnodeWeerd,謝謝,但我需要完全使用TPL庫。 – pragmus 2014-10-05 19:58:02

+0

@pragmus拋開「Parallel.For」是TPL的一部分,爲什麼你需要*直接使用TPL? – 2014-10-05 20:19:48

回答

1

counter1counter2很可能位於同一緩存行,因爲它們在內存中相鄰。這導致False Sharing。可能你經常增加這些櫃檯。這爲計數器之間的每次交替時間在兩個核心的L1之間平分了高速緩存線。

將它們分開。作爲一個概念證明,像這樣:

int counter1; 
long padding0, p1, p2, p3, p4, p5, p6, p7; //64 bytes padding 
int counter2; 

讓我們希望JIT不重新排列字段。也許你需要使用StructLayout

或者,使計數器局部變量。堆棧變量只能通過極端巧合錯誤分享。