거기에 어떤 과 같은 방법을 쓰는 시나리오 :
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
이 대신에 :
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
말이 될까요?
내부 호출 에서 return await
직접 리턴 할 때 구문을 사용하는 이유는 무엇 입니까?Task<T>
DoAnotherThingAsync()
return await
많은 곳에서 코드가 표시 됩니다. 무언가를 놓친 것 같습니다. 그러나 내가 이해하는 한,이 경우 async / await 키워드를 사용하지 않고 직접 작업을 반환하는 것은 기능적으로 동일합니다. 왜 추가 await
레이어의 오버 헤드를 추가 해야합니까?
답변
하나 부적절한 케이스가 return
정상적인 방법과 return await
에서 async
다르게 동작합니다 방법은 :와 결합 될 때 using
(또는보다 일반적으로, 임의의 return await
A의 try
블록).
다음 두 가지 버전의 메소드를 고려하십시오.
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
첫 번째 방법 것이다 객체 즉시로 실제로 완료되기 전에 긴 가능성이 메소드가 복귀. 즉, 첫 번째 버전은 버그 가 많을 수 있으며 ( 너무 빨리 폐기 되므로 ) 두 번째 버전은 제대로 작동합니다.Dispose()
Foo
DoAnotherThingAsync()
Foo
답변
필요하지 않은 경우 async
(즉, Task
직접 반품 할 수 있는 경우)를 사용하지 마십시오 async
.
두 가지 비동기 작업을 수행하는 return await
경우와 같이 유용한 상황 이 있습니다.
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
async
성능 에 대한 자세한 내용 은 Stephen Toub의 MSDN 기사 및 주제에 대한 비디오 를 참조하십시오 .
업데이트 : 나는 훨씬 더 자세히 블로그 게시물 을 작성했습니다 .
답변
await
이전 코드에 다른 것이 있거나 결과를 반환하기 전에 어떤 식 으로든 조작하려는 경우에만 그렇게해야합니다. 발생할 수있는 또 다른 방법은 try/catch
예외 처리 방식을 변경하는 것입니다. 그중 아무것도하지 않으면 옳습니다. 메소드를 만드는 오버 헤드를 추가 할 이유가 없습니다 async
.
답변
결과를 기다리는 또 다른 경우는 다음과 같습니다.
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
이 경우 두 방법간에 유형 이 다르고에 직접 할당 할 수 없기 때문에 GetIFooAsync()
결과를 기다려야합니다 . 당신이 결과를 기다리고한다면, 그것은 단지하게 되는 것입니다 직접 할당 . 그런 다음 비동기 메소드는 결과를 내부 와 외부로 다시 패키지합니다 .GetFooAsync
T
Task<Foo>
Task<IFoo>
Foo
IFoo
Task<IFoo>
답변
그렇지 않으면 간단한 “썽크”메소드를 비동기로 만들면 비동기 상태 머신은 메모리에 생성되지만 비동기 상태 머신은 그렇지 않습니다. 비효율적 인 버전을 사용하는 사람들이 종종 비효율적 인 버전을 사용하도록 지시 할 수 있지만, 더 효율적이기 때문에 중단되는 경우 해당 방법이 “반환 / 연속 스택”에 관련되어 있다는 증거가 없습니다. 때로는 중단을 이해하기가 더 어려워집니다.
따라서 perf가 중요하지 않은 경우 (그리고 일반적으로 그렇지 않은 경우) 나중에이 중단을 진단하는 데 도움이되는 비동기 상태 시스템을 사용하여 나중에 중단을 진단하고, 썽크 방식은 시간이 지남에 따라 발전해 왔기 때문에 던져지는 대신 오류가 발생한 작업을 반환해야합니다.
답변
return await를 사용하지 않으면 디버깅 중 또는 예외 로그에 인쇄 될 때 스택 추적을 망칠 수 있습니다.
작업을 반환하면 메서드가 목적을 달성했으며 호출 스택에서 벗어났습니다. 사용 return await
하면 통화 스택에 그대로 둡니다.
예를 들면 다음과 같습니다.
Await 사용시 호출 스택 : A가 B에서 작업을 기다리는 중 => B가 C에서 작업을 기다리는 중
await를 사용 하지 않을 때의 호출 스택 : A가 B가 리턴 한 C의 태스크를 기다리고 있습니다.
답변
이것은 또한 나를 혼란스럽게하며 이전 답변이 실제 질문을 간과했다고 생각합니다.
내부 DoAnotherThingAsync () 호출에서 Task를 직접 반환 할 수있는 경우 return await 구문을 사용하는 이유는 무엇입니까?
때로는 실제로를 원 Task<SomeType>
하지만 대부분의 경우 실제로 인스턴스 SomeType
, 즉 작업의 결과를 원합니다 .
코드에서 :
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
구문에 익숙하지 않은 사람 (예를 들어, 나)은이 메소드가을 리턴해야한다고 생각할 수도 Task<SomeResult>
있지만,로 표시되어 있기 때문에 async
실제 리턴 유형은 SomeResult
입니다. 을 사용 return foo.DoAnotherThingAsync()
하면 컴파일되지 않은 작업이 반환됩니다. 올바른 방법은 작업 결과를 반환하는 것입니다 return await
.
