배후의 전체 아이디어 Parallel.ForEach()
는 스레드 세트가 있고 각 스레드가 콜렉션의 일부를 처리한다는 것입니다. 알다시피, 이것은 비동기 호출 중에 스레드를 해제하려는 async
- 와 함께 작동하지 않습니다 await
.
ForEach()
쓰레드 를 막아서“수정”할 수는 있지만 async
- 의 전체 요점을 무너 뜨 await
립니다.
할 수있는 일은 대신 비동기식을 지원 하는 TPL Dataflow 를 사용 Parallel.ForEach()
하는 Task
것입니다.
특히, 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()
.
코드와 비교할 때 추가 이점으로 (작동 한 경우) 단일 항목이 완료되는 즉시 쓰기가 시작되고 모든 처리가 완료 될 때까지 기다리지 않는다는 것입니다.