有人可以向我解释一下下面两个代码示例的行为有什么区别吗? 哪一种更好/更安全? 这是存储库实现的一个片段。
任务.运行
public Task<TDocument> FindByIdAsync(string id)
{
return Task.Run(() =>
{
var objectId = new ObjectId(id);
var filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, objectId);
return _collection.Find(filter).SingleOrDefaultAsync();
});
}
异步任务
public async Task<TDocument> FindByIdAsync(string id)
{
var objectId = new ObjectId(id);
var filter = Builders<TDocument>.Filter.Eq(doc => doc.Id, objectId);
return await _collection.Find(filter).SingleOrDefaultAsync();
}
Task.Run
,如docs中所述:
将指定的工作排队在
上运行,并返回该工作的任务或ThreadPool
句柄。Task<TResult>
即在这种情况下,它将强制执行线程池上的所有代码。通常
Task.Run
用于 CPU 密集型工作负载,例如,如果 FindByIdAsync
在某些单线程 SynchronizationContext
中执行(例如在桌面应用程序的 UI 线程中),并且 SingleOrDefaultAsync
调用之前的代码计算量很大它可能会导致 UI 冻结,这是不可取的。它还处理 SingleOrDefaultAsync
不是“真正异步”的情况。
另一方面,如果您在没有同步上下文的“普通”ASP.NET Core 中调用此方法,则在这种情况下使用
Task.Run
没有多大意义,第二种方法应该更可取(它应该更性能良好,尽管在很多情况下并不那么明显)。
虽然假设这是用于查询某些数据库/存储的代码,并且客户端很可能是“真正异步”的(尽管存在一些令人讨厌的异常),但是使用第一个而不是第二个并没有多大意义。
另请参阅:
当您想要并行化 CPU 密集型工作时,第一种方法适用。但是,在异步编程的上下文中,它不是最有效的方法,因为它通过启动新任务并在不同线程上运行代码而引入额外的开销。
第二种方法更加高效,是处理异步操作的推荐方法。它不会引入不必要的上下文切换或额外的线程开销,使其成为异步代码的更好选择。
总而言之,
async/await
方法通常对于处理存储库或任何其他异步代码中的异步操作更好、更安全。
更多详细信息:Task.Run vs Async Await