2016-09-15 67 views
1

我有公開async方法,它調用3個不同的API來獲取一些數據,然後將響應發佈到下一個API。現在基於Stephen Cleary的文章here來避免死鎖:對私有異步方法使用ConfigureAwait(false)?

1.在您的「庫」異步方法中,儘可能使用ConfigureAwait(false)。
2.不要阻止任務;一直使用異步。

我想知道私人異步方法是否也是如此?當我打電話給private異步方法時,是否需要使用ConfigureAwait(false)?因此沿線

public async Task<int> ProcessAsync(ServiceTaskArgument arg) 
    { 
     // do i need to use ConfigureAwait here while calling private async method? 
     var response1 = await GetAPI1().ConfigureAwait(false); 

     // do i need to use ConfigureAwait here while calling private async method? 
     var response2= await PostAPI2(response1).ConfigureAwait(false); 

     // do i need to use ConfigureAwait here while calling private async method? 
     await PostAPI3(response2).ConfigureAwait(false); 

     return 1; 
    } 

    private async Task<string> GetAPI1() 
    { 
     var httpResponse = await _httpClient.GetAsync("api1").ConfigureAwait(false); 

     // do i need to use ConfigureAwait here while calling private async method? 
     await EnsureHttpResponseIsOk(httpResponse).ConfigureAwait(false); 

     return await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); 
    } 

    private async Task<string> PostAPI2(string data) 
    { 
     var stringContent = new StringContent(data, Encoding.UTF8, "application/json"); 
     var httpResponse = await _httpClient.PostAsync("api2", stringContent).ConfigureAwait(false); 

     // do i need to use ConfigureAwait here while calling private async method? 
     await EnsureHttpResponseIsOk(httpResponse).ConfigureAwait(false); 

     return await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); 
    } 

    private async Task<string> PostAPI3(string data) 
    { 
     var stringContent = new StringContent(data, Encoding.UTF8, "application/json"); 
     var httpResponse = await _httpClient.PostAsync("api3", stringContent).ConfigureAwait(false); 

     // do i need to use ConfigureAwait here while calling private async method? 
     await EnsureHttpResponseIsOk(httpResponse).ConfigureAwait(false); 

     return await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); 
    } 

    private async Task EnsureHttpResponseIsOk(HttpResponseMessage httpResponse) 
    { 
     if (!httpResponse.IsSuccessStatusCode) 
     { 
      var content = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); 
      throw new MyHttpClientException("Unexpected error has occurred while invoking http client.", content, httpResponse.Headers); 
     } 
    } 

UPDATE1
此外,我所經歷的東西SO發佈here,但回答提示使用自定義NoSynchronizationContextScope
我想知道是否需要在私有方法上使用ConfigureAwait(false)?

回答

3

我想知道是否需要在私有方法上使用ConfigureAwait(false)?

作爲一般規則,是的。 ConfigureAwait(false)應該用於await除非方法需要其上下文。

但是,如果您使用NoSynchronizationContextScope,則不需要ConfigureAwait(false)

+0

參考實現:http://stackoverflow.com/questions/28305968/use-task-run-in-synchronous-method-to-avoid-deadlock-waiting-on-async-method – Caramiriel

0

這取決於你的班級是什麼。它是類庫的一部分嗎?或者它是一個Web API或其他服務操作?正如Stephen提到的那樣,爲了避免死鎖,最安全的是ConfigureAwait(false),但是如果你絕對確定調用者沒有被阻塞(.Wait().Result()),例如ProcessAsync是一個asp.net web,它也可以添加很多不必要的代碼api方法。

+2

如果你真的確定代碼不需要上下文,那麼添加'ConfigureAwait'可以防止將每個單獨的延續調度到同步上下文。即使它沒有*死鎖*,它也會影響性能,並且可能會延遲實際需要同步上下文的操作的處理。特別是對於可能被大量使用的庫方法,至少其中一些用途是性能敏感的,這是值得的。 – Servy

+0

@Servy不錯的加法。我賣了:) – Kevin

+0

@Servy謝謝。如建議我將添加ConfigureAwaite(false)。但我真的很想知道爲什麼這不是.net中的默認實現。 – LP13