2012-01-27 33 views
2

我有興趣將我的函數調用定時到數據庫+其他函數,爲我的應用程序的性能構建一些指標。我使用了Stopwatch和一個度量對象,但它似乎並沒有始終給出正確的值。有時調用一個函數所用的時間與所有不現實的調用完全相同...在多線程共享的對象中實現唯一性的最佳方法是什麼?

我發現問題的原因是由於Metrics對象屬性值。當由其他線程生成的度量標準的其他實例被賦值時,其中一個Metrics對象的值將被覆蓋。雖然每個線程都創建了一個新的實例,但它看起來像屬性值是每個引用。

在多線程共享的對象中實現唯一性的最佳方法是什麼?下面

代碼:

private Metrics Metrics; 
private Stopwatch Stopwatch; 
private int DegreeOfParallelism { get { return Convert.ToInt32(ConfigurationManager.AppSettings["DegreeOfParallelism"].ToString()); } } 

var lOptions = new ParallelOptions() { MaxDegreeOfParallelism = DegreeOfParallelism }; 
Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) => 
{ 
    if (!string.IsNullOrEmpty(lItem.XmlRequest)) 
    { 
     try 
     { 
      Metrics = new Metrics(); 
      Stopwatch = new Stopwatch(); 
      Stopwatch.Start(); 
      ObjRef = new Object(); 
      lItem.XmlRequest = ObjRef.GetDecision(Username, Password); 
      Stopwatch.Stop(); 
      Metrics.ElapsedTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 

      Stopwatch.Restart(); 
      if (!string.IsNullOrEmpty(DBConnectionString)) 
      { 
       DataAccess = new DataAccess2(DBConnectionString); 
       DataAccess.WriteToDB(lItem.XmlRequest); 
      } 
      Stopwatch.Stop(); 
      Metrics.DbFuncCallTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 
     } 
     catch (Exception pEx) 
     { 
      KeepLog(pEx); 
      Metrics.HasFailed = true; 
     } 
     finally 
     { 
      ProcessedIdsBag.Add(lItem.OrderId); 
      Metrics.ProcessedOrderId = lItem.OrderId; 
      Metrics.DegreeOfParallelism = DegreeOfParallelism; 
      Metrics.TotalNumOfOrders = NumberOfOrders; 
      Metrics.TotalNumOfOrdersProcessed = ProcessedIdsBag.Count; 
      pBackgroundWorker.ReportProgress(Metrics.GetProgressPercentage(NumberOfOrders, ProcessedIdsBag.Count), Metrics); 

      RequestBag.TryTake(out lItem); 
     } 
    } 
}); 

任何幫助將是非常讚賞。 謝謝, [R

+0

「Metrics」類是什麼樣的? – 2012-01-27 15:59:57

回答

1

什麼,似乎你想要做的是爲每個迭代的度量對象,然後在最後它們聚集:

private ConcurrentBag<Metrics> allMetrics = new ConcurrentBag<Metrics>(); 
private int DegreeOfParallelism { get { return Convert.ToInt32(ConfigurationManager.AppSettings["DegreeOfParallelism"].ToString()); } } 

var lOptions = new ParallelOptions() { MaxDegreeOfParallelism = DegreeOfParallelism }; 
Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) => 
{ 
    if (!string.IsNullOrEmpty(lItem.XmlRequest)) 
    { 
     try 
     { 
      var Metrics = new Metrics(); 
      var Stopwatch = new Stopwatch(); 
      Stopwatch.Start(); 
      ObjRef = new Object(); 
      lItem.XmlRequest = ObjRef.GetDecision(Username, Password); 
      Stopwatch.Stop(); 
      Metrics.ElapsedTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 

      Stopwatch.Restart(); 
      if (!string.IsNullOrEmpty(DBConnectionString)) 
      { 
       DataAccess = new DataAccess2(DBConnectionString); 
       DataAccess.WriteToDB(lItem.XmlRequest); 
      } 
      Stopwatch.Stop(); 
      Metrics.DbFuncCallTime = string.Format("{0:0.00}", Stopwatch.Elapsed.TotalSeconds); 
     } 
     catch (Exception pEx) 
     { 
      KeepLog(pEx); 
      Metrics.HasFailed = true; 
     } 
     finally 
     { 
      ProcessedIdsBag.Add(lItem.OrderId); 
      Metrics.ProcessedOrderId = lItem.OrderId; 
      Metrics.DegreeOfParallelism = DegreeOfParallelism; 
      Metrics.TotalNumOfOrders = NumberOfOrders; 
      Metrics.TotalNumOfOrdersProcessed = ProcessedIdsBag.Count; 
      pBackgroundWorker.ReportProgress(Metrics.GetProgressPercentage(NumberOfOrders, ProcessedIdsBag.Count), Metrics); 

      RequestBag.TryTake(out lItem); 
      allMetrics.add(Metrics); 
     } 
    } 
}); 

// Aggregate everything in AllMetrics here 
+0

+1,但將'Stopwatch = new Stopwatch()'行更改爲'var ...',擺脫私有的,否則每個線程共享相同的秒錶:) – 2012-01-27 15:54:35

+0

感謝您的捕獲安德拉斯,相應編輯 – 2012-01-27 15:55:13

+0

非常感謝Chris和Andreas。我不完全確定它是否有助於在循環中執行我的聲明,因爲在嘗試之後,在某些情況下,我仍然會得到重複項。巧合似乎太好了。我曾經在某處讀過Stopwatch並不是一個適合多線程應用程序的理想類。這可能是秒錶錯誤的價值!? – Reda 2012-02-02 09:31:13

1

你需要改變你的秒錶的範圍和度量變量。

當前,每個線程共享相同的Metrics變量。只要一個線程進入try塊,它就會(正確)創建一個新的Metrics實例,但會將其放入一個共享變量(錯誤地)。所有其他線程在讀取共享變量時都會看到新實例,直到下一個線程出現並開始整個過程​​。

移動

private Metrics Metrics; 
private Stopwatch Stopwatch; 

你的循環

Parallel.ForEach(RequestBag, lOptions, (lItem, loopState) => 
{ 
    private Metrics Metrics; 
    private Stopwatch Stopwatch; 
... 

這將使通過循環每次迭代它自己的變量,在其中存儲它的對象的自己的實例只是裏面。

相關問題