task.Result와 동일한 완료된 작업을 기다리십시오.


117

현재 Stephen Cleary의 " Concurrency in C # Cookbook "을 읽고 있는데 다음 기술을 발견했습니다.

var completedTask = await Task.WhenAny(downloadTask, timeoutTask);  
if (completedTask == timeoutTask)  
  return null;  
return await downloadTask;  

downloadTask호출이고 httpclient.GetStringAsync, 그리고 timeoutTask실행된다 Task.Delay.

시간 초과되지 않은 downloadTask경우 이미 완료된 것입니다. downloadTask.Result작업이 이미 완료된 경우 반환하는 대신 두 번째 대기를 수행해야하는 이유는 무엇 입니까?


3
여기에는 약간의 맥락이 누락되어 있으며, 사람들이 책에 쉽게 접근 할 수없는 경우에는 포함시켜야합니다. 무엇 downloadTask이며 timeoutTask? 그들은 무엇을합니까?
마이크 Perrenoud

7
여기에서는 성공적인 완료에 대한 실제 확인이 표시되지 않습니다. 이 작업은 매우 잘 오류 발생 될 수 있으며,이 경우에 동작 합니다 (다를 수 AggregateExceptionResult를 통해 첫 번째 예외 대 ExceptionDispatchInfoawait). : 스티븐 Toub의 ".NET 4.5 태스크 예외 처리"에서 자세히 설명 blogs.msdn.com/b/pfxteam/archive/2011/09/28/... )
키릴 Shlenskiy

이 응답 @KirillShlenskiy해야
카슨

@MichaelPerrenoud 맞아요, 알아 주셔서 감사합니다. 질문을 수정하겠습니다.
julio.g

답변:


160

여기에 이미 좋은 답변 / 댓글이 있지만 차임에 따라 ...

내가 (또는 ) await보다 선호하는 두 가지 이유가 있습니다 . 첫 번째는 오류 처리가 다르다는 것입니다. 예외를 . 이상적으로는 비동기 코드가 특별히 원하지 않는 한 전혀 처리 할 필요가 없어야 합니다.ResultWaitawaitAggregateExceptionAggregateException

두 번째 이유는 조금 더 미묘합니다. 내 블로그에 설명으로 (그리고 책) Result/ Wait교착 상태가 발생할 수에 사용하면 더욱 미묘한 교착 상태가 발생할 수 있습니다 async방법 . 내가 코드를 읽고 있어요 그리고 내가 볼 때, Result또는 Wait, 그 즉시 경고 플래그입니다. Result/는 Wait당신이 인 경우에만 정확한지 반드시 확인 작업이 이미 완료된다. (실제 코드에서) 한 눈에보기가 어려울뿐만 아니라 코드 변경에 더 취약합니다.

Result/ 사용 Wait해서는 안된다는 말 은 아닙니다 . 내 코드에서 다음 지침을 따릅니다.

  1. 애플리케이션의 비동기 코드는 await.
  2. 비동기 유틸리티 코드 (라이브러리에 있음)는 코드가 실제로 호출하는 경우 때때로 Result/를 사용할 수 있습니다 Wait. 그러한 사용법에는 아마도 주석이 있어야합니다.
  3. 병렬 작업 코드는 ResultWait.

(1)은 일반적인 경우이므로 await모든 곳 에서 사용 하고 다른 경우는 일반 규칙의 예외로 취급하는 경향이 있습니다 .


프로젝트에서 'await'대신 'result'를 사용하여 교착 상태가 발생했습니다. 엉망인 부분에는 컴파일 오류가 없으며 잠시 후 코드가 불안정 해집니다.
Ahmad Mousavi

"이상적으로, 비동기 코드가 전혀 AggregateException 다룰 필요가해서는 안가 특별히 싶어하지 않는 한,"왜 @Stephen 당신이 설명해 주시겠습니까
vcRobe

4
@vcRobe 래퍼를 await방지하기 때문 AggregateException입니다. AggregateException비동기 프로그래밍이 아닌 병렬 프로그래밍을 위해 설계되었습니다.
Stephen Cleary

2
> "작업이 이미 완료되었다고 확신하는 경우에만 기다리십시오." .... 그럼 왜 Wait라고 부르나요?
Ryan The Leach

4
@RyanTheLeach :의 원래 목적은 Dynamic Task Parallelism 인스턴스 Wait에 결합하는 것이 었습니다 . 비동기 인스턴스 를 기다리는 데 사용하는 것은 위험합니다. Microsoft는 새로운 "Promise"유형 도입을 고려했지만 대신 기존 유형을 사용하기로 결정했습니다 . 비동기 작업에 대해 기존 유형을 재사용 할 때의 단점은 비동기 코드에서 사용해서는 안되는 여러 API를 사용하게된다는 것입니다. TaskTaskTaskTask
Stephen Cleary

12

이 책의 내용을 믿고 timeoutTask있는의 제품 이라면 이치 Task.Delay에 맞습니다.

Task.WhenAny를 반환합니다 Task<Task>. 여기서 내부 작업은 인수로 전달한 작업 중 하나입니다. 다음과 같이 다시 작성할 수 있습니다.

Task<Task> anyTask = Task.WhenAny(downloadTask, timeoutTask);
await anyTask;
if (anyTask.Result == timeoutTask)  
  return null;  
return downloadTask.Result; 

두 경우 모두 downloadTask이미 완료 되었기 때문에 return await downloadTask와 사이에 아주 작은 차이가 return downloadTask.Result있습니다. AggregateException@KirillShlenskiy가 주석에서 지적했듯이 후자는 원래 예외를 래핑하는 던질 것 입니다. 전자는 원래 예외를 다시 던질 것입니다.

두 경우 모두 예외를 처리 할 때마다 AggregateException내부 예외를 확인 하여 오류 원인을 찾아야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.