Task.Result가 .GetAwaiter.GetResult ()와 동일합니까?


328

최근에 많은 비동기 메소드를 사용하는 코드를 읽었지만 때로는 동기식으로 실행해야합니다. 코드는 다음을 수행합니다.

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

이것과 동일합니까

Foo foo = GetFooAsync(...).Result;

8
GetResult" 문서 에서이 유형과 그 멤버는 컴파일러가 사용하도록되어 있습니다." 다른 사람이 사용해서는 안됩니다.
— 쓰셨

32
이것을 "sync over async"라고하며, 작업이 어떻게 구현되는지 알지 못한다면 정말 나쁜 생각 일 수 있습니다 . 많은 경우에 즉시 교착 상태가 될 수 있습니다 (예 : MVC의 방법 async/ await방법)
— Marc Gravell


14
실제로는 생성자가 있고 구현할 필요가없는 "인터페이스"인터페이스가 있으며 모든 곳에서 비동기 메서드가 제공됩니다. 나는 그것이 왜 "위험한", "사용되지 않는"또는 "모든 비용을 피하는 것"인지 궁금하지 않고 그냥 효과가있는 것을 사용하게되어 기쁘다. 비동기 화로 엉망이 될 때마다 두통이 나옵니다.
— Larry

답변:


173

거의 요 한 가지 작은 차이점 : Task실패하면 GetResult()직접 발생한 예외 Task.Result를 throw하고을 throw합니다 AggregateException. 그러나 어느 때에 사용하는 것이 중요 async합니까? 100 배 더 나은 옵션은을 사용하는 것 await입니다.

또한을 사용하지 마십시오 GetResult(). 이것은 컴파일러가 아닌 사용자를위한 것입니다. 그러나 성가신 것을 원하지 않으면 AggregateException사용하십시오.


27
@JayBazuzi 단위 테스트 프레임 워크가 비동기 단위 테스트를 지원하지 않는다면 대부분의 프레임 워크의 최신 버전이 생각합니다.
— svick 2016 년

15
@JayBazuzi : MSTest, xUnit 및 NUnit은 모두 async Task단위 테스트를 지원 하며 얼마 동안 있습니다.
— Stephen Cleary 2016 년

18
100x를 뒤로 밀기-오래된 코드를 적용하고 await를 다시 작성 해야하는 경우 await를 사용하는 것이 1000x 나빠집니다.
— 에

13

15
The 100x better option is to use await.만약 내가 await앞에 때릴 수 있다면 나는 이와 같은 진술을 싫어한다 . 나는 자주 나에게 무슨 일 같은 비 비동기 코드에 대한 작업을 비동기 코드를 얻으려고하지만, 많은 자 마린에를, 내가 좋아하는 일을 사용할 필요 결국 ContinueWith은 UI를 교착하지 수 있도록하기 위해 많은. 편집 : 나는 이것이 오래되었다는 것을 알고 있지만, 당신이 단지 사용할 수없는 상황에 대한 대안없이 이것을 언급하는 답을 찾는 것을 완화시키지 않습니다 await.
— 토마스 F.

147

Task.GetAwaiter().GetResult()이상 선호 Task.Wait하고 Task.Result그것은 그들을 포장보다는 예외를 전파하기 때문에 AggregateException. 그러나 세 가지 방법 모두 교착 상태 및 스레드 풀 기아 문제가 발생할 수 있습니다. 그들은 모두 찬성하여 피해야한다 async/await.

아래 인용하는 이유를 설명 Task.Wait하고 Task.Result단지의 예외 전파 동작을 포함하지 않는 Task.GetAwaiter().GetResult()(인해 "매우 높은 호환성 바"로).

앞에서 언급했듯이 호환성이 매우 높기 때문에 변경 사항을 피할 수 있습니다. 따라서 Task.Wait항상 줄 바꿈의 원래 동작을 유지합니다. 그러나에 의해 사용되는 동기식 차단과 유사한 동작을 원 Task.Wait하지만 원래 예외가에 포함되지 않고 래핑되지 않은 전파를 원하는 일부 고급 상황에 처할 수 있습니다 AggregateException. 이를 위해 작업 대기자를 직접 대상으로 지정할 수 있습니다. " await task;" 를 쓰면 컴파일러는이를 Task.GetAwaiter()메서드의 사용법으로 변환하여 메서드가있는 인스턴스를 반환합니다 GetResult(). 결함이있는 작업에 사용될 GetResult()경우 원래 예외를 전파합니다 ( " await task;"의 동작 방식). 따라서 "task.GetAwaiter().GetResult()이 전파 로직을 직접 호출하려는 경우

https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

“ GetResult”은 실제로“작업에 오류가 있는지 확인”을 의미합니다

일반적으로 비동기 작업을 동 기적으로 차단하지 않으려 고 최선을 다합니다. 그러나 그 지침을 위반하는 몇 가지 상황이 있습니다. 드문 조건에서 내가 선호하는 방법은 GetAwaiter().GetResult()작업 예외를에 감싸는 대신 보존하기 때문 AggregateException입니다.

http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html


3
따라서 기본적 Task.GetAwaiter().GetResult()으로와 같습니다 await task. 메서드를 표시 할 수없는 경우 첫 번째 옵션을 사용한다고 가정합니다 async(예 : 생성자). 그 맞습니까? 그렇다면, 그것은 상단 응답과 충돌 @ It'sNotALie
— OlegI

5
@OlegI : Task.GetAwaiter().GetResult()와 동일 Task.Wait하며 Task.Result(세 가지 모두 동 기적으로 차단되고 교착 상태 Task.GetAwaiter().GetResult()가 발생할 수 있음) 대기 작업의 예외 전파 동작이 있습니다.
— Nitin Agarwal

이 시나리오에서 (Task) .ConfigureAwait (false) .GetAwaiter (). GetResult ();를 사용하여 교착 상태를 피할 수 없습니다. ?
— Daniel Lorenz

3
@DanielLorenz : 다음 인용문을 참조하십시오. "교착 상태를 피하기 위해 ConfigureAwait (false)를 사용하는 것은 위험한 방법입니다. 차단 코드에서 호출 한 모든 메소드의 전 이적 클로저에서 모든 대기 시간마다 ConfigureAwait (false)를 사용해야합니다. -및 타사 코드 : 교착 상태를 피하기 위해 ConfigureAwait (false)를 사용하는 것이 최선의 방법입니다) ... ... 더 나은 솔루션은 "비동기 코드를 차단하지 마십시오"입니다. - blog.stephencleary.com/2012/07/dont-block-on-async-code.html
— 니틴 아가 왈

4
나는 그것을 얻지 못한다. Task.Wait 및 Task.Result가 의도적으로 손상 되었습니까? 왜 구식이 아닌가?
— osexpert

69

https://github.com/aspnet/Security/issues/59

"마지막 말 : 당신은 사용하지 않아야 Task.Result하고 Task.Wait가능한 한 그들은 항상에서 내부 예외를 캡슐화로 AggregateException더 열심히 디버깅하게 일반적인 하나 (하나 이상의 오류가 발생)에 의해 메시지를 교체하더라도 동기 버전 shouldn. 자주 사용 Task.GetAwaiter().GetResult()하지 말고 대신 사용하는 것이 좋습니다. "


20
여기에 언급 된 출처는 참조없이 다른 사람을 인용하는 사람입니다. 문맥을 고려하십시오 :이 글을 읽은 후 어디서나 GetAwaiter (). GetResult ()를 맹목적으로 사용하는 많은 사람들을 볼 수 있습니다.
— Jack Ukleja

2
그래서 우리는 그것을 사용해서는 안됩니까?
— tofutim

11
두 개의 작업이 예외로 끝나는 경우이 시나리오에서 두 번째 작업을 풉니 다 Task.WhenAll(task1, task2).GetAwaiter().GetResult();.
— Monsignor

여기에 또 다른 예는 다음과 같습니다 github.com/aspnet/AspNetCore/issues/13611
— 조지 Chakhidze

33

또 다른 차이점은 async함수 Task대신에 함수가 반환 되면 Task<T>사용할 수 없다는 것입니다

GetFooAsync(...).Result;

이므로

GetFooAsync(...).GetAwaiter().GetResult();

여전히 작동합니다.

질문의 예제 코드가 사례임을 알고 Task<T>있지만 질문은 일반적으로 요구됩니다.


1
사실이 아닙니다. 정확히 다음 구문을 사용하는 바이올린을 확인하십시오. dotnetfiddle.net/B4ewH8
— wojciech_rak

3
@wojciech_rak 코드에서을 사용 Result하는 GetIntAsync()을 사용 하고 Task<int>있습니다 Task. 내 대답을 다시 읽어 보시기 바랍니다.
— Nuri Tasdemir

1
당신 말이 맞아, 처음 에는을 반환하는 함수 GetFooAsync(...).Result 안에 넣을 수 없다는 것을 이해했습니다 Task. C #에는 void 속성이 없으므로 (이것은 속성이므로) 이제는 의미 Task.Result가 있지만 void 메서드를 호출 할 수도 있습니다.
— wojciech_rak

22

이미 언급했듯이을 사용할 수 있습니다 await. 당신은 당신이 언급처럼 기적으로 코드를 실행해야하는 경우 .GetAwaiter().GetResult(), .Result또는 .Wait()교착 상태의 위험이다 많은 사람들이 의견 / 답변에서 말했듯이. 우리 대부분은 oneliners를 좋아하기 때문에 이것을 사용할 수 있습니다.Net 4.5<

비동기 메서드를 통해 값을 얻는 방법 :

var result = Task.Run(() => asyncGetValue()).Result;

비동기 메서드를 동 기적으로 호출

Task.Run(() => asyncMethod()).Wait();

사용으로 인해 교착 상태 문제가 발생하지 않습니다 Task.Run.

출처:

https://stackoverflow.com/a/32429753/3850405


1

작업에 오류가 발생하면 연속 코드가 awaiter.GetResult ()를 호출 할 때 예외가 다시 발생합니다. GetResult를 호출하는 대신 작업의 Result 속성에 간단히 액세스 할 수 있습니다. GetResult 호출의 이점은 작업이 실패하면 AggregateException에 래핑되지 않고 예외가 직접 발생하여 더 간단하고 깔끔한 catch 블록을 허용한다는 것입니다.

제네릭이 아닌 작업의 경우 GetResult ()에는 void 반환 값이 있습니다. 유용한 기능은 전적으로 예외를 다시 발생시키는 것입니다.

출처 : 간단히 말해서 c # 7.0

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