簡體   English   中英

Task.Run與直接異步調用,用於啟動長時間運行的異步方法

[英]Task.Run vs. direct async call for starting long-running async methods

有好幾次,我發現自己編寫了長時間運行的異步方法,比如輪詢循環。 這些方法可能如下所示:

private async Task PollLoop()
{
    while (this.KeepPolling)
    {
        var response = await someHttpClient.GetAsync(...).ConfigureAwait(false);
        var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

        // do something with content

        await Task.Delay(timeBetweenPolls).ConfigureAwait(false);
    }
}

為此目的使用async的目的是我們不需要專用的輪詢線程,但是(對我而言)邏輯比直接使用像計時器這樣的東西更容易理解(也就是說,不需要擔心重入)。

我的問題是,從同步上下文啟動這樣一個循環的首選方法是什么? 我能想到至少兩種方法:

var pollingTask = Task.Run(async () => await this.PollLoop());

// or

var pollingTask = this.PollLoop();

無論哪種情況,我都可以使用ContinueWith()來響應異常。 我對這兩種方法之間差異的主要理解是,第一個將首先在線程池線程上開始循環,而第二個將在當前線程上運行,直到第一個等待。 這是真的? 還有其他需要考慮的事項或更好的嘗試方法嗎?

我對這兩種方法之間差異的主要理解是,第一個將首先在線程池線程上開始循環,而第二個將在當前線程上運行,直到第一個等待。 這是真的?

是。 異步方法在第一次等待尚未完成的等待時將其任務返回給其調用者。

按照慣例,大多數異步方法返回非常快。 您也可以,因為await someHttpClient.GetAsync將很快到達。

將這個異步方法的開頭移到線程池上是沒有意義的。 它增加了開銷,幾乎沒有延遲。 它當然無助於吞吐量或擴展行為。

在這里使用異步lambda( Task.Run(async () => await this.PollLoop()) )特別無用。 它只是將PollLoop返回的任務包含在另一層任務中。 Task.Run(() => this.PollLoop())會更好。

我對這兩種方法之間差異的主要理解是,第一個將首先在線程池線程上開始循環,而第二個將在當前線程上運行,直到第一個等待。 這是真的?

是的,這是真的。

在你的場景中,似乎沒有必要使用Task.Run ,但是方法調用和第一個await之間幾乎沒有代碼,所以PollLoop()幾乎會立即返回。 不必要地將任務包裝在另一個任務中只會降低代碼的可讀性並增加開銷。 我寧願使用第二種方法。

關於其他考慮因素(例如異常處理),我認為這兩種方法是等效的。

為此目的使用async的目的是我們不需要專用的輪詢線程,但是(對我而言)邏輯比直接使用像timer這樣的東西更容易理解

作為旁注,這或多或少都是計時器無論如何都會做的。 實際上Task.Delay 使用計時器實現的!

暫無
暫無

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

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