C#效率研究
本文主要是记录研究各种C# 结构下的运行效率对比。
Linq效率测试
C#拥有Linq语句,类似与数据库操作语法。使用其中语法可以快速实现一些功能,例如排序,同时使得代码整体结构更清晰干净。
这里主要测试对几个Linq函数与通常实现的区别,并总结相关内容。Linq相关也可以参看C#语言思考部分。
对于Linq中的OrderBy来说,有两个关键点:
- 其是一个延迟结构,即只有调用的时候才会去执行排序操作。
- 其每次会产生一个新的容器列表。
OrderBy
而使用Sort接口则是原位置排序,所以对比操作如下:
|
|
方式说明 | 时间花费(ms) | 时间花费(ms) |
---|---|---|
数组个数:$10^3$ | 数组个数:$10^7$ | |
运行次数:$10^4$ | 运行次数:1 | |
Linq | 4087 | 14350 |
Sort | 1691 | 3934 |
可以看到Linq耗时还是比较高的,比copy创建List+Sort还要慢。我认为这是因为Linq不仅创建目标数组,还创建了一个中间泛型数组来做比较,称之为Sort数组。这也可以通过其接口只用一个返回Int的函数来看出,这一步相当于一部映射操作,即把对象都映射到整数上,使用整数的序关系来排序。另一方面是即便是排序操作,对于Linq来说,底层也是只有当遍历的时候才进行操作,这个可以看源码是通过一个partial quick sort来操作的。
All
Linq还有一些集合操作,可以接受一个断言函数(predict),输出集合上的对应逻辑运算的结果,例如判断全部满足的All运算。 所谓断言即输出一个true or false的函数。 显而易见的,对于Linq来说会不断调用断言函数,这种实现必定要慢一些。但是其写法更加简单,同时更加触及逻辑运算本质。此处主要记录对比会慢多少:
方式说明 | 时间花费(ms) |
---|---|
数组个数:$10^3$ | |
运行次数:$10^7$ | |
Linq | 3863 |
Loop Check | 391 |
类型转化测试
C# 作为静态类型语言。在代码层一定要带上类型结构,这就伴随着必不可少的类型转换问题。这里主要是测试一下 强转与as is等效率直接的差异而已。
运行次数:$10^9$
方式说明 | 时间花费(ms) |
---|---|
强转 | 2601 |
As转换 | 3065 |
带If判断的操作。
运行次数:$10^9$
方式说明 | 时间花费(ms) |
---|---|
as + if | 4526 |
is + if | 4319 |
可以看到效率差异其实都不是很大。只是强转如果类型不同会失败,但是as会返回null。而对于原本就是null类型,强转与as都会给出null。 实际对于架构来说,架构内部结构会要求传入的都是程序员知道类型来控制。所以强转也无大问题。但是从语义角度来讲实际还是有差异的,对于类型转换来说,实际上相当于调用了转换运算。也就是尝试将目标类型变成目标类型,例如一个类A和类B,如果定义了之间的转化关系,实际上也是可以操作的。从这个方面来讲,as则更有是的意思。从结构来说我们的架构,更多强调的是:我知道,它就是这个。所以比起转化操作,as更好一些。
Diction遍历测试
Dictionary遍历主要有两个方面,每次都是遍历Dictionary获取对应的KeyPair然后获取对应的值。还有一个是生成Key或者Value的迭代器来操作。这里主要对比两个方式的效率差异。
运行次数:$10^9$
方式说明 | 时间花费(ms) |
---|---|
foreach | 2482 |
foreach +Keys | 1946 |
可以发现单纯的遍历Keys或者Values会要快一些。这是因为虽然Keys或者Values方法虽然会生成一个中间结构来作为迭代器。但是对于遍历Dictionary实际上,会对每一个KeyValue对生成一个KeyPair对象来封装,所以会慢一点。可以参看底层数据结构部分。
IfElse测试
因为对于python等这种语言来说,对于使用?:
结构与ifelse
结构有很大的效率差异。在此决定测试一下这两者之间是否存在差异,测试代码对比如下。
|
|
运行次数:$10^9$
方式说明 | 时间花费(ms) |
---|---|
?: | 2767 |
IfElse | 4013 |
令我惊讶的是,使用?:
确实要比ifelse
快一点点。我怀疑可能是这种情况下,优化编译对于上一句直接优化导致。但是两边都添加一个对于result
的ifelse
后依然是?:
快一点点。
可能编译器内部存在着对?:
的优化吧。
基础容器结构测试
主要是想对比看一下基础容器结构之间的新能差异。例如List与Array的foreach遍历效率差异。理论来讲,两者都是基于数组的结构,只是List由C#包装了一层。
方式说明 | 时间花费(ms) |
---|---|
数组个数:$10^3$ | |
运行次数:$10^6$ | |
List | 16279 |
Array | 2170 |