如何使这个VB.NET代码更高效,更快?

时间:2012-07-28 11:49:16

标签: vb.net if-statement performance

我一直试图让这段代码在几天内变得更快,更有效,但它似乎仍然没有那么高效。

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim l As New List(Of ULong)(CType(My.Application.CommandLineArgs.Item(0), ULong))
    For i As ULong = 1 To l.Capacity
        ' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
        If l.Capacity And 1 <> 0 Then
            If i And 1 = 0 Then
                l.Add((i * i) - 1)
            Else
                l.Add((i * i) + 1)
            End If
        Else
            If i And 1 = 0 Then
                l.Add((i * i) + 1)
            Else
                l.Add((i * i) - 1)
            End If
        End If
    Next i
    Console.WriteLine(String.Join(","c, l.ToArray))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

它目前在4.3毫秒内运行100次迭代。 我觉得嵌套的if语句是这里的主要瓶颈,但我不确定我是否可以改变它们。

那么,这段代码可以提高效率吗?

谢谢...:)

2 个答案:

答案 0 :(得分:1)

首先,将If l.Capacity And 1 <> 0拉出循环,因为它总是一样。

然后,删除位操作以支持更可读的i Mod 2 = 0测试:您似乎认为这更有效,但实际上这些简单的优化最好留给编译器和运行时,它们没有位置在你的代码中,我严重怀疑他们有任何可衡量的影响。

如果仍然效率低下,请不要使用初始容量和Add。相反,使用Resize和索引访问元素。然后你也可以通过使用两个循环去除其他If语句:一个用于偶数元素,一个用于奇数元素。

那就是说, Join操作可能是迄今为止最慢的步骤(除了实际打印到控制台之外),你无能为力优化。

最后,我发现CType非常难以理解:你在这里做的不是演员 - 这是解析操作。为什么不把它写成一个呢? ULong.Parse(…)。另外,为什么你使用笨拙的My.Application.CommandLineArgs.Item而不是接受命令行参数作为Main的参数?

答案 1 :(得分:0)

一旦我只纠正了你的错误,就像我认为的那样,我在使用带有版本构建的Visual Studio 2010的Ctrl + F5时得到了这个输出:

  

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117 ,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040 ,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217 ,9408,9605,9800,10001
  33.9106

这是代码:

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim l As New List(Of ULong)(CInt(My.Application.CommandLineArgs(0)))

    For i As ULong = 1 To CULng(l.Capacity)
        ' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
        If (l.Capacity And 1) <> 0 Then
            If (i And 1UL) = 0UL Then
                l.Add((i * i) - 1UL)
            Else
                l.Add((i * i) + 1UL)
            End If
        Else
            If (i And 1UL) = 0UL Then
                l.Add((i * i) + 1UL)
            Else
                l.Add((i * i) - 1UL)
            End If
        End If
    Next i
    Console.WriteLine(String.Join(","c, l.ToArray))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

使用LINQ:

  

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117 ,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040 ,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217 ,9408,9605,9800,10001
  13.0721

那是:

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim arg = CInt(My.Application.CommandLineArgs(0))
    Console.WriteLine(String.Join(","c, Enumerable.Range(1, arg).Select(
                                  Function(i) ((i * i +
                                               If((arg And 1) <> 0,
                                                   If((i And 1) = 0, -1, 1),
                                                   If((i And 1) = 0, 1, -1))).ToString()))))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

现已优化:

  

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117 ,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040 ,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217 ,9408,9605,9800,10001
  12.5956

在这一点上,我认为我明显地在时间范围内点击Console.WriteLine方差,但即使使用下面的代码,我仍然会得到12到15毫秒......

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim arg = CInt(My.Application.CommandLineArgs(0))

    Dim fn As Func(Of Integer, String) = If((arg And 1) <> 0,
                                            Function(i As Integer) ((i * i + If((i And 1) = 0, -1, 1)).ToString()),
                                            Function(i As Integer) ((i * i + If((i And 1) = 0, 1, -1)).ToString()))

    Dim s = String.Join(","c, Enumerable.Range(1, arg).Select(fn))

    watch.Stop()
    Console.WriteLine(s)
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub