2 回答
TA贡献1820条经验 获得超9个赞
您发布的代码按顺序执行排队的项目,一次一个,但也与 Web 服务器并行。一个IHostedService正在按照定义与 Web 服务器并行运行。这篇文章提供了一个很好的概述。
考虑以下示例:
_logger.LogInformation ("Before()");
for (var i = 0; i < 10; i++)
{
var j = i;
_backgroundTaskQueue.QueueBackgroundWorkItem (async token =>
{
var random = new Random();
await Task.Delay (random.Next (50, 1000), token);
_logger.LogInformation ($"Event {j}");
});
}
_logger.LogInformation ("After()");
我们添加了 10 个等待随机时间的任务。如果您将代码放在控制器方法中,即使控制器方法返回,事件仍将被记录。但是每个项目都将按顺序执行,以便输出如下所示:
Event 1
Event 2
...
Event 9
Event 10
为了引入并行,我们必须改变的执行BackgroundProceessing的方法QueuedHostedService。
这是一个允许并行执行两个任务的示例实现:
private async Task BackgroundProceessing()
{
var semaphore = new SemaphoreSlim (2);
void HandleTask(Task task)
{
semaphore.Release();
}
while (!_shutdown.IsCancellationRequested)
{
await semaphore.WaitAsync();
var item = await TaskQueue.DequeueAsync(_shutdown.Token);
var task = item (_shutdown.Token);
task.ContinueWith (HandleTask);
}
}
使用此实现,由于每个任务等待随机时间量,因此记录的事件顺序不再按顺序排列。所以输出可能是:
Event 0
Event 1
Event 2
Event 3
Event 4
Event 5
Event 7
Event 6
Event 9
Event 8
编辑:在生产环境中以这种方式执行代码而不等待它可以吗?
我认为大多数开发人员遇到“即发即忘”问题的原因是它经常被误用。
当您执行Task使用即发即弃时,您基本上是在告诉我您不关心此函数的结果。您不关心它是否成功退出、是否被取消或是否抛出异常。但是对于大多数Tasks,您确实关心结果。
您确实希望确保数据库写入通过
您确实希望确保将日志条目写入硬盘驱动器
您确实希望确保将网络数据包发送到接收器
如果你关心结果,Task
那么即发即忘就是错误的方法。
在我看来就是这样。困难的部分是找到一个Task
你真的不关心Task
.
TA贡献2019条经验 获得超9个赞
您可以为机器中的每个 CPU 添加一次或两次 QueuedHostedService。
所以像这样:
for (var i=0;i<Environment.ProcessorCount;++i)
{
services.AddHostedService<QueuedHostedService>();
}
您可以将其隐藏在扩展方法中,并使并发级别可配置以保持整洁。
- 2 回答
- 0 关注
- 221 浏览
添加回答
举报