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.