2012-07-28 64 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