簡體   English   中英

在 Net6 Worker 進程中使用 task.Run 並行兩個后台服務可以嗎?

[英]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 中修復此行為,可能只需讓BackgroundServiceTask.Run中運行ExecuteAsync ,這樣其他人就不必這樣做了。

暫無
暫無

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

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