2017-12-29 58 views
1

스레드 Nesting await in Parallel.ForEach에는 Task.WhenAll을 사용하여 다중 (MaxDegreeOfParallelism) 비동기 작업을 병렬로 실행하고 이전 작업이 완료 될 때까지 대기하지 않는 것이 좋습니다.작업 매개 변수 포함 방법 작업 배열 예외 처리

public static Task ForEachAsync<T>(
     this IEnumerable<T> source, int dop, Func<T, Task> body) 
{ 
    return Task.WhenAll( 
     from partition in Partitioner.Create(source).GetPartitions(dop) 
     select Task.Run(async delegate { 
      using (partition) 
       while (partition.MoveNext()) 
        await body(partition.Current).ContinueWith(t => 
          { 
           //observe exceptions 
          }); 
})); 
} 

는 몸이 매개 변수가있는 경우 그리고

ids.ForEachAsync(10, async id => 
{ 
    ICustomerRepo repo = new CustomerRepo(); 
    var cust = await repo.GetCustomer(id); 
    customers.Add(cust); 
}); 

과 같이 호출, 나는 exceptions.e.g을 처리 할 때 매개 변수 값을 알고 싶어요. id에 대해 작업 본문이 실패한 경우 특정 ID에 대해 예외가 발생했음을 지정하여 예외를 기록해야합니다.

나는 Accessing values in Task.ContinueWith을 보았지만 t.IsFaulted 때 매개 변수에 액세스 할 수 없었습니다. (차단하지 않고, 즉 비동기)

마지막으로 나는 람다 체내 시도/캐치를 추가했습니다 그리고 내가 확실하지 않다 그러나

ids.ForEachAsync(10, async id => 
{ 
    try 
    { 
     ICustomerRepo repo = new CustomerRepo(); 
     var cust = await repo.GetCustomer(id); 
     customers.Add(cust); 
    } 
    catch(Exception e) 
    { 
     _logger.LogError(e,” id=“+ id); 
    } 
}); 

이 제대로 작동합니까 작동하는 것 같다. 원래 대답 suggested

나중에 저자는 VAR 전류를 사용하기 = partition.Current 전 (지속에 ContinueWith (t => {...})를 현재 사용 후 몸을 기다리고와 -.

사람이 수 접근 방식이 더있는 확인 상관 없음 단점이 방법의 각각의

답변

1

을 잘 볼 수있다 try/catchawait 포장 :?. Catch an exception thrown by an async method을 내 제안에서 더 큰 차이를 (partition.Current을 캡처하고 ContinueWith 연속으로 주입), 어쩌면 제외 캡처가 없으므로 좀 더 효율적입니다. 참여했다. 또한 좀 더 읽기 쉽고 우아하다고 생각합니다. ContinueWith은 일을하는 "오래된"방식입니다 (사전 async/await).

예에서는 예외 처리 부담이 호출자 (이 경우에는 _logger.LogError)에게 전달됩니다. 호출자가 예외 처리를 허용하는 경우를 처리하기 위해 ForEachAsync 코드 자체에 포함 된 catch-all과 반대로 원하는 것을 확인해야합니다. 다음과 같음 :

while (partition.MoveNext()) 
{ 
    try 
    { 
     await body(partition.Current) 
    } 
    catch (Exception e) 
    { 
     // of course here you don't know the type of T (partition.Current) 
     // or anything else about the operation for that matter 
     LogError("error processing: " + partition.Current + ": " + e); 
    } 
}