แนวคิดเบื้องหลังทั้งหมดParallel.ForEach()
คือคุณมีชุดของเธรดและแต่ละเธรดจะประมวลผลส่วนหนึ่งของคอลเลกชัน ตามที่คุณสังเกตเห็นสิ่งนี้ไม่สามารถใช้งานได้async
- await
ซึ่งคุณต้องการปล่อยเธรดในระหว่างการโทรแบบ async
คุณสามารถ“แก้ไข” ที่โดยการปิดกั้นForEach()
หัวข้อ แต่ที่เอาชนะจุดรวมของ-async
await
สิ่งที่คุณจะทำคือการใช้TPL DataflowแทนParallel.ForEach()
ซึ่งสนับสนุนตรงกันTask
s ดี
โดยเฉพาะอย่างยิ่งรหัสของคุณสามารถเขียนได้โดยใช้การTransformBlock
แปลงแต่ละ id เป็นการCustomer
ใช้async
แลมบ์ดา บล็อกนี้สามารถกำหนดค่าให้ดำเนินการแบบขนาน คุณจะเชื่อมโยงบล็อกนั้นกับสิ่งActionBlock
ที่เขียนแต่ละรายการCustomer
ไปยังคอนโซล หลังจากที่คุณตั้งค่าเครือข่ายบล็อกที่คุณสามารถPost()
แต่ละ ID TransformBlock
ไป
ในรหัส:
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();
แม้ว่าคุณอาจต้องการ จำกัด การขนานของTransformBlock
ค่าคงที่เล็กน้อย นอกจากนี้คุณสามารถจำกัดความสามารถของTransformBlock
และเพิ่มรายการลงในแบบอะซิงโครนัสโดยใช้SendAsync()
ตัวอย่างเช่นถ้าคอลเลกชันมีขนาดใหญ่เกินไป
ในฐานะที่เป็นประโยชน์เพิ่มเติมเมื่อเปรียบเทียบกับรหัสของคุณ (ถ้ามันทำงาน) คือการเขียนจะเริ่มทันทีที่รายการเดียวเสร็จและไม่รอจนกว่าการประมวลผลทั้งหมดจะเสร็จสิ้น