BackgroundService 是否总是在新线程中运行

Twe*_*nty 6 c# multithreading asp.net-core-3.0

因此,在ASP.Net Core的MSDN 中,它向您展示了如何使用托管服务创建后台任务。甚至还有一个特定的段落解释了如何创建后台队列。

现在我的问题是,该ExecuteAsync方法是否已经在自己的线程中运行,还是需要先调用Task.Run?

Pan*_*vos 7

Will a BackgroundService always run in a new Thread?不。

BackgroundService没有指定任何有关线程的内容。它唯一要求的是返回 a 的重载Task,只要服务启动,该重载就保持活动状态。如果需要,您甚至可以返回已完成的任务。

如果你检查源代码,你会发现根本没有假设:

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        _executingTask = ExecuteAsync(_stoppingCts.Token);

        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }

        return Task.CompletedTask;
    }
Run Code Online (Sandbox Code Playgroud)

服务方法的线程行为取决于实现者,即您。如果ExecuteAsync在让步之前阻塞,则整个服务都会阻塞。如果该方法永远不会产生,则对其自身的调用StartAsync将被阻塞并导致整个应用程序出现问题。

如果ExecuteAsync在第一个服务之前做了一些昂贵的事情await,那么其他服务的启动也会被延迟。

这意味着Task.Run如果服务在第一次屈服之前需要执行任何昂贵的操作(即第一次调用await.


Lia*_*iam 4

该ExecuteAsync方法会在自己的线程中运行吗

假设ExecuteAsync是一个async方法 ( public async Task ExecuteAsync)

Tl;Dr 这取决于

async意味着该线程可以await编辑。await会停顿主线程当前的执行,直到结果返回async。这会将当前线程释放回线程池以供重新使用。然后,当async返回时,一个新线程(可能取决于您实际如何调用它)被从线程池中拉出以继续执行。这称为上下文切换。

如果这个方法不是真正的,async那么什么也不会发生,它会像不是一个async方法一样运行。

如果此方法显式创建Task(using Task.Run) 那么async线程将创建awaitthis Task。因此,任务使用一个新线程,该async方法将释放它的线程,并在任务返回时获取一个新线程。但这并不是零和,因为上下文切换的成本很高。这就是为什么您应该只使用async IO 密集型方法,因为在 CPU 密集型进程中通常会降低效率而不是提高效率。

我建议您阅读Stephen Cleary 关于该主题的优秀博客

  • 主要问题没有答案:HostedService 是否总是在单独的线程中运行? (2认同)