2014-10-06 28 views
3

執行我有以下PLINQ查詢:進行AsParallel()順序地

// Let's get a few customers 
List<Customer> customers = CustomerRepository.GetSomeCustomers(); 

// Let's get all of the items for all of these customers 
List<CustomerItem> items = customers 
    .AsParallel() 
    .SelectMany(x => ItemRepository.GetItemsByCustomer(x)) 
    .ToList(); 

我期望GetItemsByCustomer()到並行執行鍼對每個客戶,但它依次運行

我試圖迫使並行,但仍然沒有運氣:

List<CustomerItem> items = customers 
    .AsParallel() 
    .WithExecutionMode(ParallelExecutionMode.ForceParallelism) 
    .SelectMany(x => ItemRepository.GetItemsByCustomer(x)) 
    .ToList(); 

方法簽名:

private IEnumerable<Item> GetItemsByCustomer(Customer customer) 
{ 
    // Get all items for a customer... 
} 

this article,PLINQ當然可以採取連續路線,如果它認爲合適的,但強制並行仍然應該覆蓋這一點。

注:上面的實例是純說明性的 - 假定customers爲小的列表,並GetItemsByCustomer是一種昂貴的方法。

+4

你能給出一個完整的,獨立的例子嗎? – nvoigt 2014-10-06 06:26:54

+0

您的真實代碼是否相同,或者您正在使用'SelectMany'的超載索引作爲參數? – 2014-10-06 07:00:07

+0

@SriramSakthivel:我的代碼在結構上與上面相同。 – davenewza 2014-10-06 07:05:31

回答

4

AsParallel()沒有問題。如果可能的話,它將以並行方式運行,並且LINQ表達式中沒有順序依賴關係,因此沒有任何事情可以強制它順序運行。

兩三爲什麼你的代碼不能並行運行可能的原因:

  1. 你箱/ VM有一個單一的CPU或者你有一個.NET環境的並行限制在一個CPU。你可以模擬與此代碼:

     var customers = new List<Customer>() { new Customer() {Name = "Mick", Surname = "Jagger"}, new Customer() {Name = "George", Surname = "Clooney"},new Customer() {Name = "Kirk", Surname = "DOuglas"}}; 
    
         var items = customers 
         .AsParallel() 
         .SelectMany(x => 
         { 
          Console.WriteLine("Requesting: " + x.Name + " - " + DateTime.Now); 
          Thread.Sleep(3000); 
          return new List<CustomerItem>(); 
    
         }) 
         .WithDegreeOfParallelism(1) 
         .ToList(); 
    

    即使你在單核/ CPU對話框,或當並行度是1,你的設置將不會有效果迫使paralelism與WithExecutionMode(ParallelExecutionMode.ForceParallelism),因爲真正的並行不可能。

  2. 在存儲庫中發生的共享資源上存在一些線程鎖定。您可以模擬螺紋的鎖固與下面的代碼:

    var customers = new List<Customer>() { new Customer() {Name = "Mick", Surname = "Jagger"}, new Customer() {Name = "George", Surname = "Clooney"},new Customer() {Name = "Kirk", Surname = "DOuglas"}}; 
    
        var locker = new object(); 
    
        // Let's get all of the items for all of these customers 
        var items = customers 
         .AsParallel() 
         .SelectMany(x => 
         { 
          lock (locker) 
          { 
           Console.WriteLine("Requesting: " + x.Name + " - " + DateTime.Now); 
           Thread.Sleep(3000); 
           return new List<CustomerItem>(); 
          } 
    
         }) 
         .ToList(); 
    
  3. 有是迫使查詢一些數據庫設置/讀取是在某些情況下順序,這可能給你的印象是你的C#代碼是不是並行運行,而實際上是這樣。

+1

所以,它歸結爲執行鎖定的自定義方法屬性(用於緩存)。我完全忽略了這個屬性 - 但是你的帖子讓我知道了。謝謝 – davenewza 2014-10-08 13:22:31

+0

我很高興我能幫忙! – 2014-10-08 13:28:46