82

나는 현재 "Concurrency in C #Cookbook"을 Stephen Cleary가 읽고 있는데, 나는 다음과 같은 기술을 발견했다 :

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

downloadTaskhttpclient.GetStringAsync에 대한 호출이며timeoutTaskTask.Delay를 실행 중입니다.

시간 초과되지 않은 경우 downloadTask가 이미 완료되었습니다. 작업이 이미 완료되었다는 것을 감안할 때 downloadTask.Result를 반환하는 대신 두 번째 기다리는 것이 필요한 이유는 무엇입니까?


  • 여기에는 약간의 문맥이 없기 때문에 사람들이 책에 쉽게 액세스 할 수 없으면 책을 포함시켜야합니다. 무엇입니까downloadTasktimeoutTask? 걔들 뭐해? - Mike Perrenoud
  • 성공적으로 완료되었는지 실제로 확인하지 못했습니다. 그 일은 매우 잘못 될 수 있으며, 그 경우에는 행동의지다를 것 (AggregateExceptionResult을 통해 첫 번째 예외 대ExceptionDispatchInfoawait). Stephen Toub " Task Exception Handling in .NET 4.5 "에서 자세히 논의 됨 :blogs.msdn.com/b/pfxteam/archive/2011/09/28/…) - Kirill Shlenskiy
  • 당신이 대답을해야합니다 @ KirillShlenskiy - Carsten
  • @MichaelPerrenoud 문제가 생겨서 고맙습니다. 질문을 수정하겠습니다. - julio.g

2 답변


110

이미 몇 가지 좋은 해답 / 코멘트가 있지만 여기에 나와 있습니다.

내가 좋아하는 이유는 두 가지가있다.await위에Result(또는Wait). 첫 번째는 오류 처리가 다르다는 것입니다.await예외를AggregateException. 이상적으로 비동기 코드는AggregateException전혀 그렇지 않다면~ 싶다에.

두 번째 이유는 좀 더 미묘합니다. 내 블로그 (및 책)에서 설명 할 때,Result/Wait교착 상태를 일으킬 수있다., 및에 사용될 때 더욱 세심한 교착 상태를 야기 할 수있다.async방법. 코드를 통해 읽고있을 때Result또는Wait그것은 즉각적인 경고 플래그입니다. 그만큼Result/Wait네가 괜찮다면절대적으로 확실한작업이 이미 완료되었음을 나타냅니다. 이 기능은 한눈에 (실제 코드에서) 볼 수있을뿐만 아니라 변경 내용을 코드화하는 것이 더 쉽습니다.

그 말은 아니야.Result/Wait할까요사용하십시오. 내 지침에 따라 다음 지침을 따르십시오.

  1. 응용 프로그램의 비동기 코드에서만 사용할 수 있습니다.await.
  2. 비동기 유틸리티 코드 (라이브러리에서) 가끔 사용 가능Result/Wait코드가 실제로 그것을 요구하면. 이러한 사용에는 주석이 있어야합니다.
  3. 평행작업 코드에서 사용할 수 있습니다.ResultWait.

여기서 (1)은 일반적인 경우이므로 사용하려는 경향이 있음을 주목하십시오.await모든 경우를 다루고 다른 경우를 일반적인 규칙의 예외로 취급합니다.


  • ' 결과 '를 사용하여 교착 상태가 발생했습니다. ' 기다리는 대신 ' 우리 프로젝트에서 뒤죽박죽 된 부분은 컴파일 오류가 없으며 잠시 후 코드가 불안정 해집니다. - Ahmad Mousavi
  • @Stephen은 이유를 설명해 주시겠습니까? " 이상적으로 비동기식 코드는 특별히 " - vcRobe
  • @vcRobe 때문에awaitAggregateException싸개.AggregateException비동기 프로그래밍이 아닌 병렬 프로그래밍 용으로 설계되었습니다. - Stephen Cleary
  • > " 작업이 이미 완료되었음을 절대적으로 확신하는 경우에만 대기하십시오. " .... 그럼 왜 기다리는거야? - Ryan The Leach
  • @RyanTheLeach :의 원래 목적Wait에 가입했다.동적 작업 병렬 처리 Task인스턴스. 그것을 사용하여 비동기 대기Task인스턴스는 위험합니다. Microsoft는 새로운 " 약속 " 유형을 선택했으나 기존의Task대신; 기존의 재사용의 단점Task비동기 작업의 유형은 비동기 코드에서 단순히 사용하면 안되는 여러 API로 끝나는 것입니다. - Stephen Cleary

7

이것은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 downloadTaskreturn downloadTask.Result. 후자가AggregateException코멘트에서 @KirillShlenskiy에 의해 지적 된 바와 같이 어떤 원래의 예외를 감싸고있다. 전자는 원래의 예외를 다시 던질뿐입니다.

두 경우 모두 예외를 처리 할 때마다 다음을 확인해야합니다.AggregateException오류의 원인을 알기 위해 어쨌든 내부 예외가 발생합니다.

연결된 질문


관련된 질문

최근 질문