C#访问MongoDB进行读操作时,为什么异步读比同步读要慢很多呢?

foolix 2017-11-15 04:11:42
请教各位大神,我在使用C#对MongoDB模拟大并发读的时候,使用异步发起500次读的请求,耗时7秒;但使用同步发起500次读的请求,只耗时600多毫秒。有大神知道大概是什么原因吗?
MongDb的服务器版本是3.4,C#的驱动是2.4.4版本的mongocsharpdriver。
数据访问类:
public class Dal
{
private IMongoClient client;
private IMongoDatabase database;
public static readonly Dal Instance = new Dal();
private Dal()
{
client = new MongoClient("mongodb://localhost:27017/?maxPoolSize=555");
database = client.GetDatabase("ChartPicFullChs");
//var collection = database.GetCollection<Person>("bar");
}
public TEntity Load<TEntity>(Expression<Func<TEntity, bool>> func)
{
var tableName = (typeof(TEntity)).Name;
//System.Console.WriteLine(string.Format("func{1} begin connect : {0}", DateTime.Now.ToString("HHmmssfff"), func.Body.ToString()));
var result = database.GetCollection<TEntity>(tableName).Find(func).FirstOrDefault();
//System.Console.WriteLine(string.Format("end connect : {0}", DateTime.Now.ToString("HHmmssfff")));
return result;
}
public async Task<TEntity> LoadAsync<TEntity>(Expression<Func<TEntity, bool>> func)
{
var tableName = (typeof(TEntity)).Name;
LoggerManager.Instance._Logger.Info(string.Format("begin connect : {0}", DateTime.Now.ToString("HHmmssfff")));
var result = await database.GetCollection<TEntity>(tableName).Find(func).FirstOrDefaultAsync();
LoggerManager.Instance._Logger.Info(string.Format("end connect : {0}", DateTime.Now.ToString("HHmmssfff")));
return result;
}
}
调用方法:
同步:
public void BatchTest()
{
LoggerManager.Instance._Logger.Info(string.Format("begin synchronous test {0}", DateTime.Now.ToString("HHmmssfff")));
var dal = Dal.Instance;
for (int i = 0; i < 500; i++)
{
var url = string.Format("6508_{0}_13", 3557 + i);
//System.Console.WriteLine(string.Format("begin {1} : {0}", DateTime.Now.ToString("HHmmssfff"), url));
var desc = dal.Load<image_desc>(x => x.Id == url);
image_content pic;
if (desc != null)
pic = dal.Load<image_content>(x => x.Id == desc.md5);
//System.Console.WriteLine(string.Format("end {1} : {0}", DateTime.Now.ToString("HHmmssfff"), url));
}
LoggerManager.Instance._Logger.Info(string.Format("end synchronous test {0}", DateTime.Now.ToString("HHmmssfff")));
}

异步:

public void BatchTestAsync()
{
var dal = Dal.Instance;
var urls = new List<string>();
for (int i = 0; i < 1000; i++)
{
urls.Add(string.Format("6508_{0}_13", 3557 + i));
}
LoggerManager.Instance._Logger.Info(string.Format("begin Async test {0}", DateTime.Now.ToString("HHmmssfff")));
var results = new List<Task<byte[]>>();
LoggerManager.Instance._Logger.Info(string.Format("begin add task {0}", DateTime.Now.ToString("HHmmssfff")));
foreach (var url in urls)
{
var pic = Task.Run<byte[]>(() => GetImg(url));
results.Add(pic);
}
LoggerManager.Instance._Logger.Info(string.Format("end add task {0}", DateTime.Now.ToString("HHmmssfff")));
Task.WaitAll(results.ToArray());
LoggerManager.Instance._Logger.Info(string.Format("end Async test {0}", DateTime.Now.ToString("HHmmssfff")));
}
...全文
423 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2018-05-20
  • 打赏
  • 举报
回复
应该是Task.WaitAll的原因,最外层调用也用异步试一试。 public async Task BatchTestAsync() { ....... await results.ToArray(); ....... }
foolix 2017-11-20
  • 打赏
  • 举报
回复
引用 7 楼 kampoo 的回复:
本来就应该这样啊,同步读取一定是比“异步读取”要快的,同步读取是把当前时间片全给你,“异步读取”是抢先式的可能会被其他线程抢占时间片。异步读取的优势在于能配合UI线程,不影响操作体验。如果不需要关注用户体验,尽量使用同步读取。 另外还有一种“异步读取”的体验是快的,注意是“体验”,就是数据库检索大数据量时,首页数据出现的时间很重要。次页大部分时候用户是不会打开的。这时候良好设计的数据库驱动也是另外一种“异步读取”,边读取边返回,首页数据很快,次页数据也许还在网络上传输呢。 第三种异步读取叫化整为零,不要一次读取全部数据,尽管总的累计读取时间变长了,但每次读取的时间很短,不影响数据库锁定和体验。
谢谢,对我有启发。 只是我这个慢的有点过分了,慢了近十倍。。。详细查看异步日志后,发现在异步查询执行到中后段时,会有明显的卡顿现象,如下所示: ... 2017-11-20 15:33:40 消息 end connect : 153340316 2017-11-20 15:33:40 消息 end connect : 153340316 2017-11-20 15:33:40 消息 end connect : 153340317 2017-11-20 15:33:40 消息 end connect : 153340317 ... 2017-11-20 15:33:40 消息 end connect : 153340918 2017-11-20 15:33:41 消息 end connect : 153341000 2017-11-20 15:33:42 消息 end connect : 153342606 ... 2017-11-20 15:33:42 消息 end connect : 153342708 2017-11-20 15:33:45 消息 end connect : 153345606 ... 按道理,执行到中后段,大部分的并发请求都已结束了,为什么反而开始有长时间的卡顿呢。。。
kampoo 2017-11-19
  • 打赏
  • 举报
回复
本来就应该这样啊,同步读取一定是比“异步读取”要快的,同步读取是把当前时间片全给你,“异步读取”是抢先式的可能会被其他线程抢占时间片。异步读取的优势在于能配合UI线程,不影响操作体验。如果不需要关注用户体验,尽量使用同步读取。 另外还有一种“异步读取”的体验是快的,注意是“体验”,就是数据库检索大数据量时,首页数据出现的时间很重要。次页大部分时候用户是不会打开的。这时候良好设计的数据库驱动也是另外一种“异步读取”,边读取边返回,首页数据很快,次页数据也许还在网络上传输呢。 第三种异步读取叫化整为零,不要一次读取全部数据,尽管总的累计读取时间变长了,但每次读取的时间很短,不影响数据库锁定和体验。
foolix 2017-11-19
  • 打赏
  • 举报
回复
引用 6 楼 sp1234 的回复:
循环数量不同,写日志/不写日志的流程不同,还有其它明显不同点。
谢谢,循环数量是复制异步时,用的新版本,打日志时对应的循环次数都是500,因为每次循环会有两次查询MongoDb的操作,所以是1000次查询。 日志的影响不大,异步输出日志较多是因为在发现时间差异较大后增加了它的日志输出,查看具体慢在哪里,增加日志输出后,时间未明显的增多。。。
  • 打赏
  • 举报
回复
循环数量不同,写日志/不写日志的流程不同,还有其它明显不同点。
foolix 2017-11-17
  • 打赏
  • 举报
回复
引用 3 楼 peng2739956 的回复:
by the way ,你的mongo 表不会没有加索引吧
直接使用Key查的,不然使用同步查询不会这么快,1K次查询只用了600ms
foolix 2017-11-17
  • 打赏
  • 举报
回复
引用 2 楼 peng2739956 的回复:
look this
谢谢,但好像没有看到相关联的。。。它甚至没有提到异步调用
peng2739956 2017-11-16
  • 打赏
  • 举报
回复
by the way ,你的mongo 表不会没有加索引吧
peng2739956 2017-11-16
  • 打赏
  • 举报
回复
foolix 2017-11-15
  • 打赏
  • 举报
回复
补充日志记录: 异步: 2017-11-15 15:47:56 消息 begin Async test 154756124 2017-11-15 15:47:56 消息 begin add task 154756133 2017-11-15 15:47:56 消息 end add task 154756136 2017-11-15 15:47:56 消息 begin connect : 154756145 2017-11-15 15:47:56 消息 begin connect : 154756145 2017-11-15 15:47:56 消息 begin connect : 154756145 2017-11-15 15:47:56 消息 begin connect : 154756231 2017-11-15 15:47:56 消息 begin connect : 154756333 2017-11-15 15:47:56 消息 begin connect : 154756333 ... 2017-11-15 15:48:03 消息 end connect : 154803189 2017-11-15 15:48:03 消息 end connect : 154803189 2017-11-15 15:48:03 消息 end connect : 154803190 2017-11-15 15:48:03 消息 end connect : 154803190 2017-11-15 15:48:03 消息 end connect : 154803190 2017-11-15 15:48:03 消息 end connect : 154803192 2017-11-15 15:48:03 消息 end connect : 154803192 2017-11-15 15:48:03 消息 end Async test 154803192 同步: 2017-11-15 15:43:31 消息 begin synchronous test 154331272 2017-11-15 15:43:31 消息 end synchronous test 154331957

110,571

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧