[英]Is it ok to use task.Run to parallel two backgroundservice in a Net6 Worker process?
我正在使用 Net6 和 Worker 進程(不是 asp.net )。 我需要在同一個工作進程中並行運行兩個或多個后台服務。
我用Task.Run(()=>...)
做到這一點,但我不知道這是否是一個好習慣,我會問你你對此有何看法。
所以我用兩個hostedServices創建了一個新的Worker項目:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services
.AddHostedService<Worker>()
.AddHostedService<Worker2>();
});
后台服務工作者實現:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
for (int i = 0; i < 1000; i++)
{
if (stoppingToken.IsCancellationRequested) break;
Console.WriteLine($"Worker1 - {i}");
}
}
工人2:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
for (int i = 0; i < 1000; i++)
{
if (stoppingToken.IsCancellationRequested) break;
Console.WriteLine($"Worker2 - {i}");
}
}
我會得到結果
工人1 - 1
工人 1 - 2
...
工人1 - 999
工人2 - 1
工人 2 - 2
...
工人 2 - 999
所以任務 Worker2 在 Worker 之后執行。
如果我在每個 ExecuteAsync 中使用 Task.Run:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Run(() =>
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
for (int i = 0; i < 1000; i++)
{
if (stoppingToken.IsCancellationRequested) break;
Console.WriteLine($"Worker1 - {i}");
}
});
}
和
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Run(() =>
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
for (int i = 0; i < 1000; i++)
{
if (stoppingToken.IsCancellationRequested) break;
Console.WriteLine($"Worker1 - {i}");
}
});
}
output 是
工人1 - 1
工人2 - 1
工人 2 - 2
工人1 - 1
...
這對我來說很好,但我問你使用 Task.Run 來並行化兩個后台服務是否是一個好習慣。
在某處我讀到一些關於它的東西是避免Task.Run的好習慣。 那我還應該用什么?
謝謝你。
這取決於但一般情況下(如果正在運行的進程有足夠的資源來處理所有這些),可以在一個工作項目中運行多個托管服務。
盡管您的實現有一個大問題 - ExecuteAsync
方法實際上並不是async
的,盡管它們被標記了,並且會阻塞管道直到它們結束執行。 快速修復將向它們添加await Task.Yield()
以返回控制權(您可以通過第二個示例中的await Task.Run
實現類似的效果):
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Yield();
// ....
}
請注意文檔特別提到:
避免在
ExecuteAsync
中執行長時間的阻塞初始化工作。StopAsync(CancellationToken)
中的主機阻塞等待 ExecuteAsync 完成。
您可以檢查多個工作人員的 ExecuteAsync 方法是否正在同步執行並且您的任務需要足夠的 CPU 計算,然后 Task.Run 可用於並行化
在這種情況下,如果您不需要任務的結果和異常處理,則不必等待任務完成(通過 await 運算符)。
我用 Task.Run(()=>...) 做到這一點,但我不知道這是否是一個好習慣,我會問你你對此有何看法。
使用Task.Run
是正常的,因為ExecuteAsync
否則會阻止主機啟動,正如我在博客中所描述的那樣。
他們計划在 .NET 7.0 中修復此行為,可能只需讓BackgroundService
在Task.Run
中運行ExecuteAsync
,這樣其他人就不必這樣做了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.