2014-04-17 4 views
0

ASP.NET 응용 프로그램, WCF 또는 웹 API 내에서 im은이 응용 프로그램 작업의 일부가 진행되는 동안 제 3 자에게 연락을 취한다고 가정 해 보겠습니다. Id는 비동기 적으로 또는 오히려 비 블로킹을하여 스레드 풀이 굶어 죽는 것을 좋아합니다. 그러나 나는 웹 호출을 만드는 비트 만 서비스의 모든 코드를 변경하고 싶지 않습니다.asp.net에서 비동기 웹 호출을 수행하는 방법

public string GetSomeData() 
    { 
     Task<string> stuff = CallApiAsync(); 

     return stuff.result; //does this block here? 

    } 

    private async Task<string> CallApiasync() 
    { 
     using (var httpClient = new HttpClient()) 
     { 
      string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

      return response; 
     } 

    } 

난 다음 그러나 어떤 오해를 수정하시기 바랍니다으로 아이디어라고 생각 : 여기

내가 작성한 일부 코드입니다.

CallApi 호출자가 메서드를 호출 할 수 있으며 호출 될 때까지 기다릴 때 작업이 비동기 적으로 수행되어야하는 작업을 나타내지 만 생성에는 다소 시간이 걸릴 수 있습니다. 이 시점에서 스레드는 스레드 풀로 돌아가는 기다림에 도달하여 다른 요청을 처리합니다. 즉 다른 요청을 처리합니다. 작업이 완료되면 기다림 줄이 깨어나고 코드가 동기식처럼 계속됩니다.

이 경우 내 apimethod에서 Task를 반환해야하는 이유는 무엇입니까? 호출자는 stuff.Result를 호출해야 할 것 같습니다. 작업이 완료되지 않았고 결과를 호출하는 것이 차단 될 수 있음을 의미합니다. 참고 호출 메서드를 async 너무 비동기 수 있어야 등 호출하는 메서드로 만들고 싶지 않습니다. 참고

여기 내 코드에서 이벤트 순서는 무엇입니까?

다른 질문은 왜 configureAwait를 false로 설정해야합니까? 그렇지 않으면 모든 것이 중단됩니다.

답변

6

Id는 비동기 적으로 또는 비 차단을 수행하여 스레드 풀이 굶어 죽는 것을 좋아합니다.그러나 나는 웹 호출을 만드는 비트 만 서비스의 모든 코드를 변경하고 싶지 않습니다.

그건 불가능합니다. 진정으로 비동기가 되려면 이어야하며 async은 필요한만큼 코드를 "확장"할 수 있어야합니다. 당신이하려고하는 것은 비동기 호출을 막는 것인데, 이점은 전혀 없습니다 (async을 사용하여 스레드를 풀어 버렸지 만 나중에 Result을 사용하여 스레드를 돌리고 소비하는 것입니다).

이 시점에서 스레드는 스레드 풀로 반환되어 다른 요청을 처리합니다. 즉, 다른 요청을 처리합니다.

아닙니다. async 메서드가 await에 도달하면 호출자에 불완전한 Task을 반환합니다. 호출자의 경우, 차례로, await의 해당 작업 후 불완전한 Task과의 호출 등 ASP.NET 런타임이 액션/서비스 방법에서 불완전한 Task을 받으면를 반환이/무엇이든, 다음을 스레드를 스레드 풀로 해제합니다.

따라서 async의 실질적인 혜택을 보려면 "async 끝까지"가야합니다.

좀 더 부드러운 소개와 async best practices (한 가지 : async 줄임말)에 대한 MSDN 기사는 내 블로그에 async intro이 있습니다. 또한 deadlock you were seeing을 설명하는 블로그 게시물이 있습니다.

+0

좋은 답변 지금 내가 틀린 곳을 알아 주셔서 감사합니다. 임씨는 비동기가 단순한 데모 애플리케이션 외부에서 모두 유용하다는 것을 확신하지 못합니다. 필자의 경우 웹 호출을하는 라이브러리 코드가 있지만 그 전에는 비즈니스 로직이 많이 있습니다. 즉, async/await 및 Task 이 내 코드 전체에 유출 될 것입니다. 모두 내가 그 블로킹 패션에서 일어나길 바래! 제 최선의 선택은 무엇입니까 아니면 그들이 말하는 것처럼 무료 점심이 없습니다 –

+0

최선의 선택은'async'를 포용하는 것입니다. 코드를 감염시키는 것으로 보지 마십시오. 오히려'async'는 코드의 어느 부분이 자연스럽게 비동기인지를 보여줄 것입니다. –

1

컴파일러는 비동기 패턴 뒤에있는 많은 마법을 처리하지만 구문 론적으로 "괜찮습니까? 이것은 비동기 작업입니다."라는 메서드 프로토 타입을 제공하여 원하는 것을 말하면됩니다. 기다려라. "

이 문제가 발생하려면 메서드가 Task 또는 Task<T>을 반환해야합니다. 모든 작업을 기다릴 수 있습니다.

.Result와 .Wait()를 사용할 때는 런타임이 메서드를 동 기적으로 실행하기로 결정할 수 있으므로 매우 예기치 않은 상황에서 차단할 수 있으므로주의해야합니다.

다음과 같이 말하십시오. await CallApiAsync();

이나, 실제로 활용하는 것은 :

그렇게하기 위해
Task stuff = CallApiAsync(); 

//More code that can happen independetly of "stuff" 

await stuff; 

, 당신의 GetSomeData() 함수는 또한 비동기로 표시해야하지만 그 자체로하지 않는, 돌려 태스크.

코드의 작업 비동기 버전의

완료 사본 :

공공 비동기 문자열 GetSomeData() { 작업 물건 = CallApiAsync(); 즉, CallApiAsync 기능이 이제까지 할 것입니다 모두의 경우

return await stuff; 

} 

private async Task<string> CallApiasync() 
{ 
    using (var httpClient = new HttpClient()) 
    { 
     string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false); 

     return response; 
    } 

} 

솔직히, 당신은뿐만 아니라하지만, 그것을 인라인 수 있습니다.

관련 문제