我有以下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
是一种昂贵的方法。
答案 0 :(得分:5)
AsParallel()
没有错。如果可能的话,它将以并行方式运行,并且LINQ表达式中没有顺序依赖,因此没有任何东西可以强制它顺序运行。
您的代码不能并行运行的几个原因可能是:
您的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时,您的设置也无效,因为无法实现真正的并行性。
存储库中发生的共享资源存在一些线程锁定。您可以使用以下代码模拟线程锁定:
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();
在某些情况下,有一些数据库设置强制查询/读取是连续的,这可能会让您觉得您的C#代码并非并行运行,而实际上是。