效率问题,Linq查询/多线程/反射/装箱相关

从以前msn space上搬家过来
8/31/2008 2:17:42 AM

在做ORM=>UI的框架时,对于查询,我没有直接绑定Linq返回的结果集,而是将他们转换为DataTable再绑到DataGridView上,这么做的原因有4:1、Linq结果集是单向访问的,无法让DataGrid自动对其排序。2、外键的处理,Linq直接绑到DataGrid上,外键无法显示,也可以在查询时,使用匿名类的方式创建一个新类型的结果集包含外键信息,但动态Linq的实现颇为麻烦。3、绑定后,不好确定用户选择的对象,特别是如情况2所述的做法。4、本框架的其他部分数据源主要采用DataTable形式,可能会存在交互,故此处还是采用DataTable。

于是,主要的问题就在于IQuayable到DataTable的转换了。实现不是问题,效率却是。由于是一套框架性中间组件,对于最终被应用的Linq O/R mapping类型是完全不可能知道的,所以采用反射的方式。

我的测试数据是9000条数据,5个外键,2个明细档,共20个字段。最初,没考虑性能时的实现,包括查询到显示完毕,耗时26秒。完全不可接受!

于是:做了如下调整:

多线程处理+缓存反射对象如PropertyInfo+改变dr[columnname]=xxx的赋值方式,采用LoadDataRow/Rows.Add(object[])方式,时间缩短为8.5-9.5秒

显然还是不可接受的,最初怀疑对DataTable的填充有更快的方法,通过反编译.NET Framework代码,发现MS填充DT的方式也是LoadDataRow,于是,这个可能排除。

那么,就是反射了……传说中能比直接访问效率差1000倍的反射……于是,我采用动态编译一个类,采用强类型的方式读取数据,然后写入DataTable,时间缩短为7.4秒

只提高了这么点点?!才10%?不是号称1000倍么……可见,问题不在这里。

怀疑是封箱操作占的资源,写了个测试程序,分别测试几种操作的差别和效率,结果如下:
直接调用类属性100000次,共耗费:00:00:00.0020000
直接调用类属性100000次,共耗费:00:00:00.0050000 (做封箱操作)
直接调用类属性100000次,共耗费:00:00:00.0060000 (通过外部函数)
反射调用类属性100000次,共耗费:00:00:00.7880000 (缓存反射对象)
直接调用类属性100000次,共耗费:00:00:00.0020000
直接调用类属性100000次,共耗费:00:00:00.0050000 (做封箱操作)
直接调用类属性100000次,共耗费:00:00:00.0060000 (通过外部函数)
反射调用类属性100000次,共耗费:00:00:00.8060000 (缓存反射对象)

速度基本上是稳定的,封箱操作要比强类型慢2.5倍,而通过外部函数访问外加封箱操作则慢3倍,而反射……则是400倍……(看来1000倍的说法是夸张了,但这里缓存了反射对象,否则的话也许更慢)。

其实还有人提出了通过委托来解决反射的效率问题,不过这仅仅适用于方法调用和对一个对象调用多次的情况。

那么问题到底在哪里……ADO.NET填充一个dt,9000行数据最多也就1秒了吧……我就算多了层linq,外加外键的延时加载,2-3秒应该够了吧。外加别的因素,如子线程可能优先级没主线成高- -?我在填充时还提供了Progress的委托事件(界面上进度条显示),再加1秒……4秒应该能搞定了吧?

反复尝试,最终还是停留在7.4秒……无奈下,加了个分页功能,好歹维持在一页1-2秒吧……

不过,最终还是把目光放在了延迟加载的问题上,经过sql的跟踪,发现每笔记录都会去加在明细档,恍然大悟,我添加了一个额外的自定义属性,剩余金额=总金额-明细中已付金额之和。原来是这里读的明细档。作了个试验,去掉了这个属性,作了一次查询,4秒……很好,在可接受范围内了。看来真是这玩艺导致的问题。

当然,这是最终项目的设计逻辑上的问题,而非框架层的问题,至少……我可以说,Linq结果集->DataTable的转换,我这已经没什么优化方案了。即便也许转为Dt并非最优解。但基于之前4个原因,这样的转换还是有必要的。

最终,应用层上,我的解决办法是,添加一个剩余金额的字段,在保存记录时,计算该值并一起保存。不过由于这个应用层的失误,导致花了近2天来处理效率问题,还都是无用功,真有些郁闷。但对于各种方式的效率差,也有了一定认识,还是值得的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值