2013-09-05 2 views
5

내가 내 프로그램에서 실현하고자하면 다음 호출 스택/워크 플로우입니다 :교착 비동기를 사용하여 & 기다리고

  1. 파견()
  2. 권한 부여()
  3. httpPost()

제 생각에는 httpPost()은 비동기식이고 나머지 두 가지 방식은 비동기식으로 남아 있습니다. 그러나, 2. + 3을 만들지 않으면 어떤 이유로 든 작동하지 않습니다. 비동기. 어쩌면 아직도 약간의 오해가 있습니다. 비동기 방식 (이 방법을 중단하고 비동기 방식이 완료된 후 계속)를 호출 할 때 내 이해에

나는 중 하나)을 await 개의 키워드를 사용할 수 있습니다, 또는 b)는 await 개의 키워드 ommit 대신 작업을 호출합니다. 비동기 메소드의 결과는 결과를 사용할 수있을 때까지 블록됩니다.

private int dispatch(string options) 
    { 
     int res = authorize(options).Result; 
     return res; 
    } 

    static private int authorize(string options) 
    { 
     string values= getValuesFromOptions(options); 

     Task<KeyValuePair<int, string>> response = httpPost(url, values); 

     doSomethingWith(response.Result); // execution will hang here forever 

     return 0; 
    } 

    public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> parameters) 
    { 
    var httpClient = new HttpClient(new HttpClientHandler()); 

    HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)); 

    int code = (int)response.StatusCode; 

    response.EnsureSuccessStatusCode(); 

    string responseString = await response.Content.ReadAsStringAsync(); 

    return new KeyValuePair<int, string>(code, responseString); 
    } 

나는 모든이 시도 :

private int dispatch(string options) 
    { 
     int res = authorize(options).Result; 
     return res; 
    } 

    static async private Task<int> authorize(string options) 
    { 
     string values= getValuesFromOptions(options); 

     KeyValuePair<int, string> response = await httpPost(url, values); 

     return 0; 
    } 

    public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> parameters) 
    { 
    var httpClient = new HttpClient(new HttpClientHandler()); 

    HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)); 

    int code = (int)response.StatusCode; 

    response.EnsureSuccessStatusCode(); 

    string responseString = await response.Content.ReadAsStringAsync(); 

    return new KeyValuePair<int, string>(code, responseString); 
    } 

은 내가 당신에게 - 작업 예를 보여 드리죠 :


내가 당신에게 작업 예를 보여 드리죠 비동기가 아닌 3 가지 방법을 사용하고 awaithttpPost.Result s를 입력하십시오. 그러나 계속해서 라인에 걸릴 것입니다. HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)).Result;

누군가가 나를 깨우 치고 내 실수를 설명 할 수 있습니까?

답변

11

당신은 SynchronizationContext을 가지고 있으며 await 때 해당 컨텍스트에서 캡처 할 수 있도록 해당 컨텍스트에서 계속 실행할 수 있습니다.

비동기 작업을 시작하고 나중에 주 컨텍스트에서 실행할 연속체를 예약합니다.

그런 다음 비동기 작업이 완료되기 전에 주 컨텍스트에 비동기 작업을 차단 대기하는 코드가 있습니다. 컨텍스트가 계속 대기 중으로 바쁠 때까지 계속 실행을 예약 할 수 없습니다. 고전적인 교착 상태.

첫 번째 예제에서와 마찬가지로 "항상 비동기"하는 것이 중요합니다.

두 번째 예제에서 교착 상태를 해결할 수있는 몇 가지 해킹이 있지만 여전히해야 할 일은 아닙니다. 비동기로가는 것은 스레드를 차단하지 않는 것입니다. 어쨌든 작업을 블로킹 대기 상태로 만들면 비동기로 전환 할 목적을 잃게됩니다. 선택의 여지가 없다면 모든 것을 비동기로 만들거나 비동기로 만들지 마십시오.

+0

이것이 올바른 설명인지 테스트하려면 작동하지 않는 코드를 가져 와서 "await X"를 "a.X.ConfigureAwait (false)"로 변경하십시오. 설명이 맞으면 이제 작동합니다. 또 다른 메모 : ASP.Net 또는 UI 응용 프로그램에서 실행중인 경우 SynchronizationContext가 있습니다. 그렇다면 독립 실행 형 콘솔 프로젝트에서 동일한 코드를 실행하는 것을 비교하십시오. – danarmak

+1

@servy : 그러나 내가 얻지 못하는 것은 내 작업 예제와 비 작동 예제 간의 실제 차이점입니다. '.Result'가 그냥 평범하게 블록하는 동안'await'이 연속을 가리킨다는 것을 이해합니다. 그러나 이것은'await'없이 블록/교착 상태가 발생하기 때문에 끝이없는 비동기 기다리는 체인이 필요하다는 것을 의미하지 않습니다. 내 스레드? 첫 번째 예제가'int res = authorize (options) .Result;'에서 블록하지 않는다는 것을 의미하지만, 두 번째 예제는'doSomethingWith (response.Result);에서 블록을한다. – user826955

관련 문제