现在的位置: 首页 > 综合 > 正文

试用“停表”高精度计时

2013年03月11日 ⁄ 综合 ⁄ 共 1691字 ⁄ 字号 评论关闭
转载链接:http://blog.joycode.com/ninputer/archive/2004/07/31/29167.aspx

.NET Framework 2.0中增加了一项新的诊断工具——“停表”StopWatch类,相比以前的计时系统,停表采用的是高精度计时方式,因此对性能测量更有帮助。为了试用 StopWatch类,我选择了一个经典的测试题目,VB中的IIf函数。IIf函数与C系列的?:三元运算符十分相似,可以在一行语句内完成判断和赋值 两项任务。但是,IIf是函数而不是运算符,其接受Object类型参数这一项已经够让人担忧的了。IIf到底有多慢呢?我们比较三个版本。首先是VB类 库中的Object版:

Public Function IIf(Expression As Boolean, _
    TruePart As Object, FalsePart As Object)As Object

第二个版本,是我编写的泛型版本的IIf,这个版本可以用于减少装箱拆箱过程带来的性能损失:

Public Function IIf(Of T)(Expression As Boolean, _
    TruePart As T, FalsePart As T)As T
    If Expression Then
        Return TruePart
    Else
       Return FalsePart
    End If
End Function

第三个版本当然是直接使用If语句。我们已经很清楚哪个比较快,但是没有一个量的概念,通过高精度计时的测试,可以让我看到函数内联化带来的收益是否够多。下面是计时和测试的代码:

Dim watch As New System.Diagnostics.Stopwatch

Dim j As Integer = 0
Dim f As Boolean = True

'Loop 10 times and get the average time
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        j = Interaction.IIf(f, i, 5)
    Next
    watch.Stop()

Next

GC.Collect()

TextBox1.AppendText("Object IIf: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

watch.Reset()
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        j = IIf(f, i, 5)
    Next
    watch.Stop()

Next

GC.Collect()

TextBox1.AppendText("Generic IIf: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

watch.Reset()
For times As Integer = 1 To 10

    watch.Start()
    For i As Integer = 0 To 1000000
        If f Then j = i Else j = 5
    Next
    watch.Stop()

Next

TextBox1.AppendText("Pure If: " & watch.ElapsedMilliseconds / 10 & vbCrLf)

我们看到StopWatch可以像真的停表一样开始,停止或继续,因此我们可以像在科学实验中计时一样使用它。而他的Elapsed属性可以提供各种单位的时间间隔。简单起见,我就用了毫秒。循环的次数不太多,取10次平均。最后的结果在我的机器上如下:

Object IIf: 219.6
Generic IIf: 51.5
Pure If: 9.7

纯If仅9.7毫秒的间隔也能测试出来,足见StopWatch的精度比原来的计时手段高多了。而结果也表明,函数调用的代价已经相当可观,但还不 如装箱、拆箱带来的代价高。IIf当然是不要再用了,今后自己写函数时也应当注意,频繁调用的函数不能不考虑调用代价,内联化是不错的解决方案。

抱歉!评论已关闭.