查找和FindAsync之间的区别

35

我正在编写一个非常简单的查询,它根据唯一的文档ID从集合中获取文档。在经历了一些挫折之后(我刚开始使用MongoDB和异步/等待编程模型),我弄清楚了这件事:

IMongoCollection<TModel> collection = // ...
FindOptions<TModel> options = new FindOptions<TModel> { Limit = 1 };
IAsyncCursor<TModel> task = await collection.FindAsync(x => x.Id.Equals(id), options);
List<TModel> list = await task.ToListAsync();
TModel result = list.FirstOrDefault();
return result;

它很好用!但我一直看到提到“Find”方法的参考资料,我已经搞清楚了:

IMongoCollection<TModel> collection = // ...
IFindFluent<TModel, TModel> findFluent = collection.Find(x => x.Id == id);
findFluent = findFluent.Limit(1);
TModel result = await findFluent.FirstOrDefaultAsync();
return result;

事实证明,这也起作用,太棒了!

我相信我们有两种不同的方法来实现这些结果,肯定有重要的原因。这些方法之间有什么区别,为什么我应该选择其中一种?


1
async 关键字通过其调度程序“管理”您的代码,这可以但不总是使您的应用程序多线程化。await 关键字向编译器发出信号,以便在好的时机决定并切换上下文或利用新线程。 - whoisj
async 关键字并不会使你的应用程序多线程化。请参见此处。这不是关于 C# 的问题,而是有关 MongoDB C# API 中可用方法的差异。 - object88
如果你不立即await,那么“FindAsync”不能使你的应用程序多线程运行?如果你不立即await,有很大的可能会实现多线程。 - John Saunders
3
不会创建线程。使用 asyncawait 不会创建后台线程,也不会使线程休眠。asyncawait 的整个意图是放弃对线程的控制,以便消息循环可以在同一线程上处理另一个排队的消息。如果您等待的内容本身没有在另一个线程上运行或自动执行后台请求,则添加 await 不会导致它运行在另一个线程上。一个不适合使用 await 的反例是计算密集型函数。 - object88
2个回答

55

区别在于语法。 FindFindAsync都允许使用相同的性能构建异步查询。

FindAsync 返回游标,它不会一次性加载所有文档,并提供检索DB游标中每个文档的接口。在查询结果巨大时很有帮助。

Find通过方法ToListAsync提供了 更简单的语法,其中内部从游标中检索文档并一次性返回所有文档


所以,在我的特定情况下,没有有效的区别,因为我只是以任何方式加载一个文档。对于大批量文档,听起来我应该使用游标(也许不要跟随它使用 ToListAsync,因为那样会加载所有文档?)。这个评估公平吗? - object88
1
对于一个文档来说,“查找”功能更好,因为你不需要使用光标。 - rnofenko
我理解了你的回答,我很好奇所描述的差异是否与前一种情况中接受的选项对象是通用的有关(即FindAsync(...,options: FindOptions<T> _)),而后一种情况则不是通用的(即Find(...,options: FindOptions _))。在我的情况下,这非常重要,因为通用的那个具有投影字段,而另一个则没有。 - Konrad Viltersten
此外,在使用FindAsync时,执行后查询已经发送到数据库,而Find不会立即发送,只有在尝试枚举结果时才会发送(例如:使用ToListAsync)。 - dandev486

0

想象一下,您在Web请求中执行此代码,并调用find方法,请求的线程将被冻结,直到数据库返回结果为止。这是同步调用,如果它是一个需要几秒钟才能完成的长时间数据库操作,则将有一个可用于服务Web请求的线程什么也不做,只是等待数据库返回结果,并浪费宝贵的资源(线程池中的线程数是有限的)。

使用FindAsync时,您的Web请求线程将在等待数据库返回结果时保持空闲,这意味着在数据库调用期间,此线程可以自由地处理另一个Web请求。当数据库返回结果时,代码继续执行。

对于像从文件系统读取/写入、数据库操作、与其他服务通信等长时间操作,使用异步调用是一个好主意。因为在等待结果时,线程可用于服务另一个Web请求。这更具可扩展性。

请参阅此Microsoft文章https://msdn.microsoft.com/en-us/magazine/dn802603.aspx


2
两段代码都是异步的。在第一个示例中,有两个等待:一个在 FindAsync 上,另一个在 ToListAsync 上。在第二个示例中,只有一个等待:在 FirstOrDefaultAsync 上。我想知道的不是异步/等待的好处(我知道了),而是不同代码路径中可能会阻塞的部分是什么?在什么情况下最好使用 FindAsync 和 ToListAsync,而不是使用 FirstOrDefaultAsync? - object88
这段代码是否有效?使用find方法时不需要使用toList,因为它只返回找到的第一个对象。https://msdn.microsoft.com/zh-cn/library/x0b5b5bc(v=vs.110).aspx - Marc Cals
我稍微扩展了一下代码以澄清问题。 - object88
抱歉 - Collection 不是 System.Collections.Generic.List<T> 对象。进一步澄清... - object88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接