簡體   English   中英

如果線程正在等待異步操作完成,.NET任務線程的資源是否會暫時返回到池中?

[英]Are a .NET Task thread's resources returned back to the pool temporarily if the thread is waiting on an async operation to finish?

我有一個TPL任務,做兩件事。 首先,它調用Web服務。 其次,它將一些數據插入數據庫。 我一次啟動多達20個任務一次又一次地做同樣的事情。 他們全天所做的就是調用Web服務並將數據插入數據庫。

我對.NET中的TPL很新。 我已經完成了一些后台工作進程和異步Web服務。

Web服務調用和數據庫插入都是在運行任務的線程內阻塞調用。

據我所知,在使用Tasks時,.NET會為您管理一個線程池。 是?

如果我使用async和await()進行服務調用和數據庫調用而不是使它們阻塞調用,那么線程池是否可以使用更多的線程?

我的理論(我不確定我為什么這么認為)是線程在等待阻塞Web服務時忙於什么都不做,並且無法將其資源臨時返回到池中。 但我想知道任務是否在等待異步調用來完成主要任務線程是否能夠在等待時切換到讓其他東西處理。

我的理論是對的嗎? 或者我在做什么?

我正在使用c#和.NET 4.0,但如果需要,我可以使用4.5。

如果我使用async和await()進行服務調用和數據庫調用而不是使它們阻塞調用,那么線程池是否可以使用更多的線程?

這取決於“使用async-await”的含義。

當您在幕后使用Task.RunTask類使用ThreadPool使用ThreadPool線程卸載工作。

如果您的服務沒有暴露真正的異步api並且您使用Task.Run對您的工作進行排隊,那么無論使用async-await ,您仍將阻止線程Task.Run線程執行IO綁定工作。 在你的問題中,你聲明兩個調用都是阻塞調用,在這種情況下答案是否定的,用於阻止調用的線程池線程仍然會被阻止。

如果您的服務和數據庫調用是真正的異步API(不使用任何額外線程來執行其工作),您可以利用async-await ,就像await其中一個調用一樣(並且您不需要)在任何情況下使用Task.Run,​​當前線程將控制權返回給調用者,並且可以同時用於做更多的工作。 如果是這種情況,那么是的。

我的理論(我不確定我為什么這么認為)是線程在等待阻塞Web服務時忙於什么都不做,並且無法將其資源臨時返回到池中。 但我想知道任務是否在等待異步調用來完成主要任務線程是否能夠在等待時切換到讓其他東西處理。

你的理論是正確的。 如果排隊的線程池工作的主要工作是發出IO綁定請求,那么它的大部分時間花費只是阻塞直到請求完成。

await Task ,控制權返回給調用者。 讓我們假設您的服務調用是一個REST調用,您可以使用HttpClient公開真正的非線程消耗異步方法,如GetAsyncPostAsync ,當您await這些調用時,您的調用線程將被釋放以同時執行更多工作。

如果所有應用程序的任務都阻止,則每個任務都將使用線程池中的線程。

如果所有任務都定期await ,則線程池不需要為每個任務使用線程。

當您的代碼await尚未完成的操作時,將保存方法的狀態,以便可以在任何其他線程上恢復該狀態。

空閑的線程池線程在一段時間后釋放,因此當調用await的方法仍在運行時,可以從線程池釋放命中await的實際線程。

將所有這些放在一起,異步版本的例程可以用更少的線程完成相同的工作(假設工作負載有足夠的時間平衡等待與旋轉CPU)。

此代碼運行100個執行同步等待的任務:

var numTasks = 100;
for (int i = 0; i < numTasks; i++)
{
    Thread.Sleep(5);
    Task.Run(() =>
    {
        Thread.Sleep(5000);
        Interlocked.Decrement(ref numTasks);
    });
}
while (numTasks > 0) Thread.Sleep(100);

對於異步等待,將其更改為:

    Task.Run(async () =>
    {
        await Task.Delay(5000);
        Interlocked.Decrement(ref numTasks);
    });

在我的系統上,異步版本將峰值線程數增加了一半,並且花費20%的時間來執行相同的“工作”。

答案是肯定的。 雖然從技術上講,它並沒有“等待”異步操作完成(否則對異步沒有任何好處)。 在引擎蓋下有一個回調委托,它在異步操作完成時運行,這使得你的調用線程可以不受阻塞地繼續運行。 這是異步/等待魔法,將這些“延續”變成線性的代碼片段。

因為您正在使用線程池線程,當它命中等待時,線程將返回到線程池。 這里需要注意的是,正常的行為是等待操作完成時它將嘗試返回到它啟動的線程(現在可能被其他任務使用),因此您可能會發現延遲問題結果回來,因為線程池線程現在被綁定啟動其他任務。 隨着時間的推移,線程池將嘗試調整可用線程的數量以滿足需求,但是如果你的工作突然發生,你可能會發現這種情況不會很快發生。 結果顯然是性能不佳,因為您可能只有少量線程可用。

暫無
暫無

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

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