簡體   English   中英

TPL可以在多個線程上運行任務嗎?

[英]Can the TPL run the Task on more than one thread?

Mono / Xamarin特定的答案受到歡迎。

我正在使用Task.Run()運行System.Threading.Tasks。 TPL是否會在任務執行期間將創建的任務分配給單個線程? 或者創建的任務是否可能在運行時被搶占,然后再次在另一個線程上安排?

Thread.CurrentThread.ManagedThreadId會在任務的生命周期內保持不變嗎?

對於長期運行的任務,答案是否不同?

有沒有辦法控制這方面的TPL行為?

Task.Run將調度委托在線程池中執行,並且線程池將只在單個線程上執行給定的委托。 它不會在線程之間移動它。

也就是說,一個Task概念上僅僅是在未來某個時刻完成某些異步操作的表示。 它可以代表最終完成的任何事情 如果要在一個線程上創建表示一個委托的執行的任務,然后在另一個線程上執行另一個委托,那么您絕對可以這樣做。

使用async關鍵字的許多方法實際上都會這樣做。 因為,在沒有設置同步上下文的應用程序中,作為await調用的結果連接的連續可以(它們有時可以被優化)每個在線程池中單獨調度。 例如,在控制台應用程序中運行的以下代碼生成的任務可能會打印出三個完全不同的數字。 (當然,它們不需要不同;線程池可能恰好安排在同一個線程上運行的延續。)

public static async Task Foo()
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    await Task.Delay(100);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    await Task.Delay(100);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

TPL是否會在任務執行期間將創建的任務分配給單個線程?

指南是工作的同步部分在單個線程上運行。 因此,如果將同步委托傳遞給Task.Run ,它將全部在單個線程上運行:

await Task.Run(() => Thread.Sleep(5000)); // same thread after sleep

但是,如果您有異步代碼,則每個await都是代碼中掛起方法的位置。 當方法恢復時,它將在線程池線程(可能是不同的線程)上恢復。

await Task.Run(async () => await Task.Delay(5000)); // thread may change

長時間運行的標志(不能傳遞給Task.Run )不會影響此行為,因為它僅適用於第一個同步部分。

控制此操作的TaskScheduler方法是使用自定義TaskSchedulerSynchronizationContext 但是,在走這條路之前,您可能想要考慮另一種方法。 應該有一個更好的解決方案,而不是強迫該方法回到同一個線程。 例如,線程仿射同步原語都具有async兼容的等價物,線程局部存儲可以被閉包/類字段/邏輯調用上下文等替換。

暫無
暫無

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

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