2011-03-23 74 views
1

我不在.NET 4上。列表分割和征服 - 按值或引用傳遞

我從數據源中得到一個巨大的列表。當列表中元素的數量高於X我想分區列表時,將每個分區分配給一個線程。在處理分區後,我喜歡合併它們。

  var subsets = list.PartitionEager(50000); 

      //var subsets = list.Partition<T>(50000); 

      Thread[] threads = new Thread[subsets.Count()]; 
      int i = 0; 
      foreach (var set in subsets) 
      { 
       threads[i] = new Thread(() => Convertor<T>(set)); 
       threads[i].Start(); 
       i++; 
      } 

      for (int j = 0; j < i; j++) 
      { 
       threads[j].Join(); 
      } 

轉換器方法是一個靜態方法,它需要一個列表並進行一些查找。

public static void Convertor<T>(List<T> list) where T : IInterface  { 

     foreach (var element in list) 
     { 
      **// do some lookup and assing a value to element 
      // then do more lookup and assign a value to element** 
     } 

    } 

當我運行此代碼時,即使我知道大多數元素將被賦值。事實上他們回來了。

我知道該列表的副本將傳遞給該方法,但元素的任何更改都應該反映在上方法中。然而這隻發生在最後一個子集內。

我甚至添加了一些代碼將列表合併成一個代碼。對於paritioning

   list.Clear(); 

       foreach (var set in subsets) 
       { 
        list.AddRange(set); 
       } 

代碼:

​​

我到底做錯了什麼?如何解決這個問題?我希望元素在查找後分配值?這與同步或參數傳遞有關嗎?

+0

你的分區算法的代碼是什麼? – 2011-03-23 22:15:53

+0

另外,每組中的值不能爲空,你對他們做了什麼? – 2011-03-23 22:16:29

+0

我做了一個對象查找並將結果附加到對象。即使查找失敗,我附加一個默認值。所以它不應該是空的。 – DarthVader 2011-03-23 22:18:05

回答

2

看起來你創建線程時有modified closure。如果我是正確的,那麼你所有的線程都會更新同一個(最後一個)集合。用這種方法修改代碼:

 foreach (var set in subsets) 
     { 
      var setLocalCopy = set; 
      threads[i] = new Thread(() => Convertor<T>(setLocalCopy)); 
      threads[i].Start(); 
      i++; 
     } 
+0

但我如何處理本地副本?轉換器將值分配給對象。 – DarthVader 2011-03-23 22:19:19

+1

@user,它不會是整個列表的本地副本,它只是'set'引用的副本。它仍會更新您正在更新的相同項目。 – Snowbear 2011-03-23 22:21:00

+1

謝謝。就是這樣。那麼這裏的教訓是什麼?爲什麼會發生? – DarthVader 2011-03-23 22:28:15

3

如果.NET 4是一個選項,您可以使用Parallel.ForParallel.ForEach。這些方法會自動爲您處理分區,並在不同系統上的多個併發度的可伸縮性方面提供許多其他優勢。

+0

我不在.net 4 – DarthVader 2011-03-23 22:16:05

+0

@ user177883:您也可以通過安裝Rx Extensions來完成此操作,因爲它們包含這些方法。 – 2011-03-23 22:16:55