簡體   English   中英

如果我以昂貴的方法返回Task,是否應該添加async修飾符?

[英]Should I add the async modifier if I return a Task in an expensive method?

如果我們有一個具有async修飾符但不使用await運算符的方法,則C#編譯器已經警告我們。

根據這個答案,沒有必要在異步方法的末尾添加一個await (在這種情況下,只需刪除async修飾符即可)。

但是,如果該方法需要執行昂貴的同步操作,然后再調用后續的真正異步方法,該怎么辦?

例如,如果我使用HttpClient

private readonly HttpClient client = ...

public Task<HttpResponseMessage> CallMyWebServiceMethod() {

    HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();

    return this.client.SendAsync( request );
}

此代碼將阻止調用方(由於SomeExpensiveButSynchronousMethod )。

但是,如果我將代碼更改為此:

public async Task<HttpResponseMessage> CallMyWebServiceMethod() {

    HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();

    return await this.client.SendAsync( request );
}

我這樣稱呼它:

HttpResponse response = await myWrapper.CallMyWebServiceMethod();

...我知道TPL會立即啟動后台線程,然后在后台線程中運行CallMyWebServiceMethod ,恢復父代碼想要的任何內容,使整個調用在該過程中成為非阻塞狀態,然后在Task完成並返回HttpResponse

...如果是這種情況,那似乎是矛盾的。

如果我錯了,並且調用一直阻塞,直到到達SendAsync那么如何在與HttpClient用於其請求的同一后台線程上執行SomeExpensiveButSynchronousMethod

根據這個答案,沒有必要在異步方法的末尾添加一個await(在這種情況下,只需刪除async修飾符即可)。

這太簡單了。 參見我關於消除異步和等待的博客文章。

但是,如果該方法需要執行昂貴的同步操作,然后再調用后續的真正異步方法,該怎么辦?

這種情況很少見,但是IMO的適當解決方案是同步執行同步操作(即,不包裝在Task.Run ),並確保記錄其行為

我知道TPL會立即啟動后台線程,然后在后台線程中運行CallMyWebServiceMethod,恢復父代碼想要的任何內容,使整個調用在該過程中成為非阻塞狀態,然后在Task完成並返回HttpResponse之后繼續執行。

那根本不會發生什么。 您可能會發現我的async介紹很有幫助。 引用:

異步方法的開始與其他方法一樣執行。 也就是說,它會同步運行,直到達到“ await”(或引發異常)為止。

實際上,您的兩個示例在執行SomeExpensiveButSynchronousMethod 同步阻塞了調用者。

如果我錯了,並且調用一直阻塞,直到到達SendAsync,那么如何在與HttpClient用於其請求的同一后台線程上執行SomeExpensiveButSynchronousMethod?

HttpClient的請求不使用后台線程,因此問題的這一部分沒有意義。 有關異步I / O如何工作的更多信息,請參見我的博客文章There No Thread

要回答實際問題:

如果我以昂貴的方法返回Task,是否應該添加async修飾符?

是。 但是,您這樣做的原因不是“使其異步”; 這樣一來,將捕獲SomeExpensiveButSynchronousMethod中的所有異常並將其放置在返回的Task ,這是遵循基於任務的異步模式(TAP)的方法的預期語義。

我知道TPL會立即啟動后台線程,然后運行CallMyWebServiceMethod

不,那不會發生。 async方法的第一個同步部分是async執行的。 如果要確保它不會阻塞當前線程,則應使用Task.Run()

您昂貴的方法將以兩種方式阻止調用者。 async不會神奇地為您創建線程,這就是Task所做的(有時)。 因此,如果添加async並等待SendAsync ,則只會不必要地增加狀態機的開銷。

另請參閱http://blog.stephencleary.com/2016/12/eliding-async-await.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM