在ASP.Net Core的MSDN中,它展示了如何使用托管服务创建后台任务。甚至有一个特定段落解释了如何创建后台队列。
现在我的问题是,
现在我的问题是,
ExecuteAsync
方法是否会在自己的线程中运行,还是我需要先调用Task.Run
?ExecuteAsync
方法是否会在自己的线程中运行,还是我需要先调用Task.Run
?BackgroundService
是否始终在新线程中运行? 不是。
BackgroundService
并未指定任何关于线程的内容。它唯一要求的是提供一个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;
}
ExecuteAsync
在产生yield之前被阻塞,则整个服务都会被阻塞。如果该方法从未产生yield,则调用StartAsync
本身将被阻塞,并对整个应用程序造成问题。ExecuteAsync
在第一个await
之前执行了一些昂贵的操作,则启动其他服务也将被延迟。await
,则可能需要使用Task.Run
。ExecuteAsync
是一个async
方法(public async Task ExecuteAsync
),那么它是否在自己的线程中运行取决于具体情况。简而言之,async
意味着这个线程可以被await
。当执行await
时,主线程的当前执行会被挂起,直到async
返回结果。这将释放当前线程回到线程池以供重新使用。然后,当async
返回时,将从线程池中拉出一个新线程(也许取决于实际调用方式)继续执行。这称为上下文切换。如果这个方法不是真正的async
,那么什么也不会发生,它会像非async
方法一样运行。Task
(使用Task.Run
),那么async
线程将await
此Task
。因此,任务使用新线程,并且在任务返回时async
方法将释放其线程并获得一个新线程。这不是零和游戏,因为上下文切换是昂贵的。这就是为什么您应该只async
IO绑定方法,因为在CPU绑定过程中通常会失去效率而不是获得效率。从异步编程开始
对于I/O绑定的代码,您需要在async方法中等待返回Task或Task的操作。
对于CPU绑定的代码,您需要使用Task.Run方法在后台线程上启动操作。
因此,如果您的ExecuteAsync
方法是I/O绑定的(根据名称看起来是I/O绑定),则不需要调用Task.Run
但是,当该方法是CPU绑定的时(即您的代码正在执行计算),则应调用Task.Run
在后台运行。
Task.Run
吗? - TwentyTask.Run
将是无用的。 - Twenty