LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C# LongRunningTask-正確用法

freeflydom
2025年8月8日 9:4 本文熱度 379

在上一篇文章《如何正確實現一個 BackgroundService》中有提到 LongRunning 來優化后臺任務始終保持在同一個線程上。

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            return Task.Factory.StartNew(async () =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    // Simulate some work
                    Console.WriteLine("HostServiceTest_A is doing work.");
                    LongTermTask();
                    await Task.Delay(1000, stoppingToken); // Delay for 1 second
                }
                Console.WriteLine("HostServiceTest_A task done.");
            }, TaskCreationOptions.LongRunning);
        }
        private void LongTermTask()
        {
            // Simulate some work
            Console.WriteLine("LongTermTaskA is doing work.");
            Thread.Sleep(30000);
        }

但是被 大佬指出這個用法是錯誤的:以上用法并不能保證任務始終在同一個 Task(線程) 上執行。原因是當碰到第一個 await 之后運行時會從 ThreadPool 中調度一個新的線程來執行后面的代碼,而當前線程被釋放。這個時候就不符合我們使用 LongRunning 的期望了。

在 .NET 中,Task.Factory.StartNew 提供了 TaskCreationOptions.LongRunning 選項,很多開發者會用它來啟動長時間運行的任務,并且想當然的認為它會永遠執行在同一個線程上。但是事實上當遇到 async await 的時候并想象的那么簡單。

下面我們還是通過一個錯誤的示例開始講解如何正確的使用它。

錯誤用法

很多人會直接在 Task.Factory.StartNew 里傳入一個 async 方法:

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
var task = Task.Factory.StartNew(async () =>
{
    Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    var loopCount = 1;
    while (true)
    {
        Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
        await LongRunningJob();
        Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
        loopCount++;
    }
}, TaskCreationOptions.LongRunning);
static async Task LongRunningJob()
{
    Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    await Task.Delay(1000);
}
Console.ReadLine();

輸出:

Hello, World!
long running task starting. Thread id: 12
Start: loop count: 1, Thread id: 12
task doing. Thread id: 12
End: loop count: 1, Thread id: 11
Start: loop count: 2, Thread id: 11
task doing. Thread id: 11
End: loop count: 2, Thread id: 11

可以看到,第一次循環后,線程 id 發生了變化。很明顯 LongRunning 失效了。原因開篇已經講了,不在贅述。

正確用法 1:同步方法

LongRunningJob 改為同步方法,避免異步切換線程:

var task = Task.Factory.StartNew(() =>
{
    Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    var loopCount = 1;
    while (true)
    {
        Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
        LongRunningJob();
        Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
        loopCount++;
    }
}, TaskCreationOptions.LongRunning);
static void LongRunningJob()
{
    Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    Thread.Sleep(1000);
}

輸出:

Hello, World!
long running task starting. Thread id: 12
Start: loop count: 1, Thread id: 12
task doing. Thread id: 12
End: loop count: 1, Thread id: 12

線程 id 始終不變,說明始終運行在專用線程上。

正確用法 2:異步方法同步等待

如果必須用異步方法,可以用 .Wait() 讓調用變為同步:

var task = Task.Factory.StartNew(() =>
{
    Console.WriteLine($"long running task starting. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    var loopCount = 1;
    while (true)
    {
        Console.WriteLine($"\r\nStart: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId}");
        LongRunningJob().Wait();
        Console.WriteLine($"End: loop count: {loopCount}, Thread id: {Thread.CurrentThread.ManagedThreadId} \r\n ");
        loopCount++;
    }
}, TaskCreationOptions.LongRunning);
static async Task LongRunningJob()
{
    Console.WriteLine($"task doing. Thread id: {Thread.CurrentThread.ManagedThreadId}");
    await Task.Delay(1000);
}

輸出:

Hello, World!
long running task starting. Thread id: 12
Start: loop count: 1, Thread id: 12
task doing. Thread id: 12
End: loop count: 1, Thread id: 12

總結

  • TaskCreationOptions.LongRunning 適用于同步、阻塞型任務。
  • 不要在 StartNew 里直接用 async 方法。
  • 如果必須用異步方法,需同步等待(如 .Wait())。

希望本文能幫你正確理解和使用 LongRunning 任務!

轉自https://www.cnblogs.com/kklldog/p/19022317


該文章在 2025/8/8 9:04:45 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
天天在线高清手机看片 | 亚洲欧美国产国产一区二区 | 亚洲色精品vr一区区三区 | 日本免费综合网... 日本一道综合久久aⅴ免费 | 日韩亚洲欧美国产动漫在线观看 | 中文字幕三级免费片 |