2014-10-06 20 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