2012-07-28 62 views
-1

我一直试图让这段代码更快,更高效几天,但现在看起来效率并不高。如何让此VB.NET代码更高效更快?

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语句是这里的主要瓶颈,但我不确定是否有任何方法可以改变它们。

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

谢谢... :)

+0

为什么在度量console.write? string.join会不会比字符串生成器更好/更快,并且在最后转储? – 2012-07-28 11:55:21

+3

您正在测量Console.WriteLine()的速度。是的,它很慢。不是一个问题,它只需要和人类一样快就可以阅读。 – 2012-07-28 16:48:02

+1

使用Option Strict On将您的代码粘贴到默认的新控制台项目中,可以突出显示代码中的许多问题。在尝试优化代码之前,您需要确保代码正在做你想做的事情! – 2012-07-30 07:50:48

回答

1

首先,拉If l.Capacity And 1 <> 0圈外的,因为它总是将是相同的。

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

如果仍然效率低下,请不要使用初始容量和Add。而是使用Resize并对元素进行索引访问。然后,您还可以使用两个循环来摆脱其他If语句:一个用于偶数元素,另一个用于奇数元素。

这就是说,Join操作可能是目前为止最慢的一步这里(除了实际打印到控制台,也许)和有什么可以做,以优化。

最后,我找到CType可怕不可读:你在做什么这里就不投 - 这是一个解析操作。为什么不把它写成一个呢? ULong.Parse(…)。另外,为什么你使用笨拙的My.Application.CommandLineArgs.Item而不是接受命令行参数作为Main的参数?

0

有一次,我只是纠正你的错误,因为我认为你打算,我用Ctrl + F5时使用Visual Studio 2010发布版本得到如下的输出:

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,3 480,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