Arkasındaki tüm fikir Parallel.ForEach(), bir dizi iş parçacığına sahip olmanız ve her iş parçacığının koleksiyonun bir bölümünü işlemesidir. Fark ettiğiniz gibi, bu, zaman uyumsuz çağrı süresi boyunca iş parçacığını serbest bırakmak istediğiniz async- ile çalışmaz await.
Bunu, ForEach()iplikleri engelleyerek “düzeltebilirsiniz” , ancak bu async- ' nun bütün noktasını yener await.
Yapabileceğiniz şey , asenkronleri iyi destekleyen TPL Dataflow'u kullanmaktır .Parallel.ForEach()Task
Özellikle, kodunuz TransformBlockher kimliği lambda Customerkullanarak bir dönüştüren bir kullanılarak yazılabilir async. Bu blok paralel çalışacak şekilde yapılandırılabilir. Bu bloğu ActionBlock, her Customerbirini konsola yazan bir bloğa bağlarsınız. Engelleme ağını kurduktan sonra, Post()her kimliğiTransformBlock .
Kodda:
var ids = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
var getCustomerBlock = new TransformBlock<string, Customer>(
async i =>
{
ICustomerRepo repo = new CustomerRepo();
return await repo.GetCustomer(i);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
var writeCustomerBlock = new ActionBlock<Customer>(c => Console.WriteLine(c.ID));
getCustomerBlock.LinkTo(
writeCustomerBlock, new DataflowLinkOptions
{
PropagateCompletion = true
});
foreach (var id in ids)
getCustomerBlock.Post(id);
getCustomerBlock.Complete();
writeCustomerBlock.Completion.Wait();
Muhtemelen paralelliğini TransformBlockbazı küçük sabitlerle sınırlamak isteseniz de . Ayrıca, örneğin koleksiyon çok büyükse, öğesinin kapasitesini sınırlayabilir TransformBlockve öğeleri eşzamansız olarak ekleyebilirsiniz SendAsync().
Kodunuzla karşılaştırıldığında (işe yaradıysa) ek bir avantaj olarak, yazı tek bir öğe biter bitmez başlayacak ve tüm işlemler bitinceye kadar beklemeyecektir.