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 TransformBlock
her kimliği lambda Customer
kullanarak 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 Customer
birini 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 TransformBlock
bazı küçük sabitlerle sınırlamak isteseniz de . Ayrıca, örneğin koleksiyon çok büyükse, öğesinin kapasitesini sınırlayabilir TransformBlock
ve öğ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.