【问题标题】:Difference between Find and FindAsyncFind 和 FindAsync 之间的区别
【发布时间】:2015-08-19 11:18:10
【问题描述】:

我正在编写一个非常非常简单的查询,它只是根据其唯一 ID 从集合中获取文档。经过一番挫折(我是 mongo 和 async / await 编程模型的新手),我想通了:

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;

效果很好,太好了!但我不断看到对“查找”方法的引用,我解决了这个问题:

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

事实证明,这也很有效,太棒了!

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

【问题讨论】:

  • async 关键字允许编译器通过其调度程序“管理”您的代码。这可以但不会总是使您的应用程序多线程。 await 关键字向编译器发出信号以决定和切换上下文或利用新线程。
  • async 特别使您的应用程序成为多线程的。见here。这不是关于 C# 的问题,而是 MongoDB C# API 可用方法的差异。
  • FindAsync 不会让您的应用程序多线程是什么意思?如果您不立即await,它很有可能会这样做。
  • 不,如果您阅读我发布的链接,您会发现使用 asyncawait 将明确创建线程。它不会创建后台线程,也不会使线程进入睡眠状态。 asyncawait 的全部意义在于放弃对线程的控制,以便消息循环可以在同一线程上处理另一个排队的消息。如果你是awaiting 本身并没有在另一个线程上运行或本质上执行后台请求,添加await 不会导致它。使用await的反例是一个CPU绑定函数。

标签: c# mongodb mongodb-query mongodb-csharp-2.0


【解决方案1】:

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

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

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

看看这篇微软文章https://msdn.microsoft.com/en-us/magazine/dn802603.aspx

【讨论】:

  • 不过,这两段代码都是异步的。在第一个示例中,有两个等待:一个在 FindAsync 上,一个在 ToListAsync 上。在第二个中,只有一个等待:在 FirstOrDefaultAsync 上。我想知道的不是 async / await 的好处是什么(我明白了),而是不同代码路径的潜在阻塞部分是什么?在某些情况下使用 FindAsync 和 ToListAsync 比 FirstOrDefaultAsync 更好吗?
  • 这段代码有效吗?使用 find 不需要 toList 因为它只返回它找到的第一个对象msdn.microsoft.com/en-us/library/x0b5b5bc%28v=vs.110%29.aspx
  • 我稍微扩展了代码以澄清问题。
  • 抱歉 -- 集合不是 System.Collections.Generic.List 对象。进一步澄清...
【解决方案2】:

区别在于语法。 FindFindAsync 都允许构建具有相同性能的异步查询,只是

FindAsync 返回cursor,它不会一次加载所有文档,并为您提供从数据库游标中逐一检索文档的界面。这在查询结果很大的情况下很有帮助。

Find 通过方法ToListAsync 为您提供更简单的语法,它在其中从光标检索文档并一次返回所有文档

【讨论】:

  • 因此,在我的特定情况下,没有有效的区别,因为无论哪种方式我都只加载一个文档。在大量文档的情况下,听起来我想使用光标(也许不跟ToListAsync,因为那样会加载所有文档?)。这是一个公平的评估吗?
  • 对于一个文档 Find 看起来更好,因为您不使用光标。
  • 我理解您的回答,我很好奇所描述的差异是否与前一种情况下接受的选项对象是通用的这一事实有关(即FindAsync(...,options: FindOptions&lt;T&gt; _) 和非通用的后者(即Find(...,options: FindOptions _)。在我的情况下,它有很大的不同,因为通用的有一个用于预测的字段,而另一个没有。
猜你喜欢
  • 2015-10-03
  • 1970-01-01
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多