我正在尝试创建一个函数来创建 ItemObj,然后导入一些与其相关的请求。问题是它使用外部 API 带来大量数据,这使得这一步变慢。
我们希望将导入保留在后台,而 UI 仍然可以使用。
public async Task<ItemObjDto> CreateItemObjAsync(ItemObjViewModel itemObjViewModel)
{
var itemObj = CreateItemObj(itemObjViewModel);
itemObjRepository.AddAsync(itemObj);
await itemObjRepository.SaveAsync();
// This import should happen in the background
_requestAppService.ImportRequestsAsync(itemObj.Id);
return _mapper.Map<ItemObjDto>(itemObj);
}
我看过很多帖子都提出了这样的建议:
await Task.Run(() =>
{
_requestAppService.ImportRequestsAsync(itemObj.Id);
});
但是,如果我将它与等待一起使用,它不会变得异步,如果我删除它,它就会出现错误,因为它无法正确保存。由于某种原因,我什至无法正确调试它,因为它不会在 try/catch 中停止,无论是在它周围,还是在 _requestAppService 内部。
我还在这篇文章中看到了一种更复杂的方法来解决这个问题:https://stackoverflow.com/a/63429262,但我在尝试让它通过导入请求调用我的 appService 时遇到了一些麻烦。 .
我想知道这两种解决方案是否是我正在寻找的,以及您是否可以告诉我我做错了什么
如果我将它与等待一起使用,它不会变得异步,并且如果我 删除它,它会变得有问题,因为它无法正确保存。而对于 出于某种原因,我什至无法正确调试它,因为它不会停止 在 try/catch 中,既不在它周围,也不在 _requestAppService 内部。 我想知道这两种解决方案是否是我正在寻找的 如果你能告诉我我做错了什么
根据您的场景和描述以及共享代码片段,我发现了一些不一致的代码,这些代码有缺点,可能导致异常输出或性能缺陷。
当你的任务是
Task.Run(())
时,你使用了await,这是不推荐的。因为,在 Task.Run 块中使用 await 可能效率低下,甚至会损害应用程序的性能和响应能力。
最重要的是,
Task.Run's
的目的是将非 UI 工作从线程池卸载到后台线程上。因此,在 Task.Run 中添加 await 本质上会阻塞后台线程,同时等待另一个操作完成。
此外,当您在 Task.Run 中等待时,您会在后台线程和调用线程之间反复切换。这种上下文切换会增加开销,并对应用程序的整体性能产生负面影响。
因此,您可以修改代码如下:
public async Task<ItemObjDto> CreateItemObjAsync(ItemObjViewModel itemObjViewModel)
{
var itemObj = CreateItemObj(itemObjViewModel);
itemObjRepository.AddAsync(itemObj);
await itemObjRepository.SaveAsync();
_ = Task.Run(async () =>
{
await _requestAppService.ImportRequestsAsync(itemObj.Id).ConfigureAwait(false);
});
return _mapper.Map<ItemObjDto>(itemObj);
}
注意: 请记住,这不是您遇到的问题的确切解决方案。但它肯定会大幅提高您的应用程序性能。另外,你可以使用
ConfigureAwait(false)
来避免死锁。请参阅此官方文档了解更多信息。