【问题标题】:AsParallel() executing sequentiallyAsParallel() 顺序执行
【发布时间】:2014-10-06 06:23:05
【问题描述】:

我有以下 PLINQ 查询:

// 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 是一个昂贵的方法。

【问题讨论】:

  • 你能举一个完整的、独立的例子吗?
  • 你的真实代码是一样的还是你使用SelectMany的重载,它以索引为参数?
  • @SriramSakthivel:我的代码在结构上与上面的相同。
  • 此外,您还应该指定如何衡量您的执行以得出结论它没有并行运行?
  • 不要尝试使用并行来加速缓慢的数据访问代码!看起来您的代码尝试在通常使用 single 连接的 ORM 上下文上“并行”执行查询。这将强制所有查询按顺序执行。不要尝试执行多个查询,而是使用 ORM 的机制将所有请求批处理到单个请求,或者创建一个 GetItemsByCustomers 方法,该方法接受您要使用的所有 ID 的列表并在 WHERE 子句中使用 IN (...) 参数

标签: c# .net linq task-parallel-library plinq


【解决方案1】:

AsParallel() 没有任何问题。如果可能,它将尽可能并行运行,并且您的 LINQ 表达式中没有顺序依赖关系,因此没有什么可以强制它顺序运行。

您的代码不能并行运行的几个原因可能是:

  1. 您的 box/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 机器上使用WithExecutionMode(ParallelExecutionMode.ForceParallelism) 强制并行化,或者当并行度为 1 时,您的设置也不会生效,因为不可能实现真正的并行化。

  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# 代码没有并行运行的印象,而实际上是并行运行。

【讨论】:

  • 所以,它归结为一个自定义方法属性(用于缓存),它正在执行锁定。我完全忽略了这个属性 - 但你的帖子让我明白了。谢谢
  • 很高兴能帮上忙!
猜你喜欢
  • 1970-01-01
  • 2012-11-23
  • 2018-08-12
  • 2013-11-12
  • 2012-04-10
  • 2013-04-11
  • 1970-01-01
  • 2017-02-10
  • 2011-04-12
相关资源
最近更新 更多