从以下考虑了异步/等待的(简化)接口开始,我想使用LiteDB数据库来实现它。
public interface IDataService
{
Task<User> GetUserAsync(int key);
}
不幸的是,LiteDB当前不支持异步方法。所有方法都是同步的。
我尝试了以下操作,但是后来遇到了一些问题(进程实际上并没有因为任何原因而等待)。之后,我读到您应该只将Task.Run()
用于CPU约束算法,而不是数据库访问。
public Task<User> GetUserAsync(int key)
{
var task = Task.Run(() =>
{
return _users
.Find(x => x.Key == key)
.SingleOrDefault();
});
return task;
}
即使我阅读了几篇博客文章以及SO问题,但我仍然不清楚如何为基于同步IO的代码编写正确编写的等待方法。
那么我该如何编写适当的等待方法?
注意:我无法更改界面。给出了。
答案 0 :(得分:7)
您不得使用Task.Run
。这不是在道德上做正确的事的问题。正如您所注意到的,在道德上将工作线程分配给不受CPU约束的任务是错误的,但这不是这里的问题。这里的问题是LiteDB是单线程的,并且在尝试将对它的调用移动到工作线程时,并不是很健壮。
更新:据一位评论员说,显然LiteDB在版本4中是线程安全的,他可能比我更了解此问题。因此,请查阅LiteDB文档以了解什么是线程安全的种类。并非所有线程安全对象都可以不受任何线程限制地使用。
您的选择是:
FromResult
是正确的方法。满足您所有所述限制的解决方案是最后一个。这也是最适合您的一项。就像木工说的那样:节省廉价材料后,您将在劳动力上花费。尝试将正确的异步接口改型为非异步但受I / O约束的单线程库是一个棘手的问题。祝你好运!
答案 1 :(得分:2)
一种选择是使用Task.FromResult
并同步实现您的界面。
return Task.FromResult(_users.Find(x => x.Key == key).SingleOrDefault());
async/await
的收获是使用I / O完成端口,该端口挂起线程并允许它处理其他传入请求,直到等待的I / O操作完成。看来您的实现无法利用此功能将您的工作包装在Task.Run
或类似物中是没有好处的。