Async await 키워드는 ContinueWith 람다와 동일합니까?


81

Async await 키워드를 올바르게 이해했는지 누군가가 친절하게 확인해 주시겠습니까? (CTP 버전 3 사용)

지금까지 메서드 호출 이전에 await 키워드를 삽입하면 기본적으로 A. 즉시 반환을 생성하고 B를 생성합니다. 비동기 메서드 호출이 완료되면 호출되는 "연속"을 생성합니다. 어쨌든 연속은 메서드에 대한 코드 블록의 나머지 부분입니다.

그래서 제가 궁금한 것은이 두 비트의 코드가 기술적으로 동일합니까? 그렇다면 기본적으로 await 키워드가 ContinueWith Lambda를 생성하는 것과 동일하다는 것을 의미합니까 (즉, 기본적으로 컴파일러 바로 가기)? 그렇지 않다면 차이점은 무엇입니까?

bool Success =
    await new POP3Connector(
        "mail.server.com", txtUsername.Text, txtPassword.Text).Connect();
// At this point the method will return and following code will
// only be invoked when the operation is complete(?)
MessageBox.Show(Success ? "Logged In" : "Wrong password");

VS

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text ).Connect())
.ContinueWith((success) =>
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password"));

답변:


83

일반적인 아이디어는 정확합니다. 나머지 메서드는 일종의 연속으로 만들어집니다.

"빠른 경로"블로그 포스트는 방법에 대한 자세한 내용이 있습니다 async/의 await컴파일러 변환 작업을.

내 머리 위의 차이점 :

await키워드는 또한 "일정 컨텍스트"개념을 사용합니다. 스케줄링 컨텍스트는 SynchronizationContext.Current존재하는 경우에 폴백됩니다 TaskScheduler.Current. 그런 다음 예약 컨텍스트에서 연속이 실행됩니다. 따라서 더 가까운 근사값은으로 전달 TaskScheduler.FromCurrentSynchronizationContext하여 필요한 경우 ContinueWith다시 떨어지는 것 TaskScheduler.Current입니다.

실제 async/ await구현은 패턴 일치를 기반으로합니다. 작업 이외의 다른 것을 대기 할 수있는 "대기 가능"패턴을 사용합니다. 몇 가지 예로는 WinRT 비동기 API,, YieldRx Observable 과 같은 일부 특수 메서드 및 GC에 강하게 영향을주지 않는 특수 소켓 awaitable이 있습니다. 작업은 강력하지만 기다릴 수있는 유일한 작업은 아닙니다.

또 하나의 사소한 차이가 떠 오릅니다. awaitable이 이미 완료된 경우 async메서드는 실제로 해당 지점에서 반환되지 않습니다. 동기식으로 계속됩니다. 따라서 통과하는 것과 비슷 TaskContinuationOptions.ExecuteSynchronously하지만 스택 관련 문제가 없습니다.


2
아주 잘 말했습니다-나는 Jon의 게시물이 너무 광범위하기 때문에 내가 대답을 할 시간이있을 것보다 훨씬 더 광범위하기 때문에 연기하려고 노력하지만 Stephen의 절대적으로 옳습니다. awaitable (특히 GetAwaiter) 무엇 WRT는, 자신의 게시물 # 3은 매우 도움이 이럴 :)입니다 msmvps.com/blogs/jon_skeet/archive/2011/05/13/...
제임스 매닝

4
여기에 스티븐의 자리. 간단한 예에서는 async / await가 ContinueWith의 지름길이라고 생각하기 쉽습니다. 그러나 저는 반대로 생각하고 싶습니다. Async / await는 실제로 ContinueWith를 사용하는 데 사용했던 것의 더 강력한 표현입니다. 문제는 ContinueWith (...)가 람다를 사용하고 실행이 연속으로 전송되도록 허용하지만 루프와 같은 다른 제어 흐름 개념은 루프 본문의 절반을 ContinueWith (.. .) 및 나머지 절반. 수동 연속 체인으로 끝납니다.
Theo Yaung

7
async / await가 ContinueWith (...)보다 훨씬 더 표현적인 또 다른 예는 예외의 흐름입니다. 동일한 try 블록 내에서 여러 번 기다릴 수 있으며, 각 실행 단계에서 예외를 명시 적으로 수행하는 수많은 코드를 작성하지 않고도 동일한 catch (...) 블록으로 전달 될 수 있습니다.
Theo Yaung

2
주목할만한 async / await의 마지막 부분은 이것이 "상위 수준의 개념"이라는 점입니다. 반면 ContinueWith (...)는 더 수동적이고 명시 적으로 람다, 델리게이트 생성 등을 포함합니다. 더 높은 수준의 개념을 사용하면 최적화를위한 더 많은 기회가 있습니다. 예를 들어, 동일한 메서드에서 여러 개의 awaits가 실제로 동일한 람다 클로저를 "공유"하는 반면 (단일 람다의 오버 헤드와 유사) ContinueWith (...)는 명시 적으로 람다를 작성했기 때문에 호출 할 때마다 오버 헤드를 가져옵니다. 그래서 컴파일러는 당신에게 그것을 제공합니다.
Theo Yaung

1
@MobyDisk : 명확하게 말하면 항상 그랬던 것처럼 await캡처합니다 SynchronizationContext.Current. 그러나 ASP.NET 핵심에 SynchronizationContext.Current있다 null.
Stephen Cleary

8

그것은 "본질적으로"그것이지만 생성 된 코드는 그 이상을 수행합니다. 생성 된 코드에 대한 자세한 내용을 보려면 Jon Skeet의 Eduasync 시리즈를 적극 권장합니다.

http://codeblog.jonskeet.uk/category/eduasync/

특히 게시물 # 7은 생성되는 항목 (CTP 2 기준)과 그 이유에 대해 설명하므로 현재 찾고있는 항목에 매우 적합 할 것입니다.

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

편집 : 나는 그것이 당신이 질문에서 찾고있는 것보다 더 자세 할 것이라고 생각하지만 방법에서 여러 번 기다릴 때 상황이 어떻게 생겼는지 궁금하다면 게시물 # 9에서 다룹니다. :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/

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