【问题标题】:Is vb.net slow?vb.net 慢吗?
【发布时间】:2018-12-26 17:41:14
【问题描述】:

我在下面用 Visual Studio 2015 准备了用 Vb.net 和 C# 编写的相同项目。 Visual Basic 项目:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim j As Int32 = 0
    '
    Dim Offset As Double = 0D   ' Offset
    Dim Gain As Double = 1D     ' Gain
    Dim Freq As Double = 1D     ' Frequency
    Dim M As Int32 = 3000    ' Number of Block
    Dim N As Int32 = 30000    ' Number of data each block
    Dim delta As Double = 0     ' Sample rate
    Dim DataCount As Int32 = N * M  ' Total data count   
    '
    Dim X As Double
    Dim Y As Double
    '
    delta = N / DataCount
    '
    ' Fonksiyon
    '
    Dim Time As Stopwatch
    Time = New Stopwatch
    Time.Start()
    '
    For b As Int32 = 0 To M - 1
        For i As Int32 = 0 To N - 1
            X = j * delta
            Y = Offset + Gain * Math.Cos(X * Freq * Math.PI / 180.0)
            j = j + 1
        Next
    Next b
    '
    Time.Stop()
    Console.WriteLine("Elapsed time :{0}", Time.Elapsed)
End Sub

和 C# 项目:

 private void button1_Click(object sender, EventArgs e)
    {

        Int32 j = 0;

        Double Offset = 0D;  // Offset
        Double Gain = 1D;     // Gain
        Double Freq = 1D;     // Frequency
        Int32 M = 3000;    // Number of Block
        Int32 N = 30000;    // Number of data each block
        Double delta = 0;     // Sample rate
        Int32 DataCount = N * M;  // Total data count   
        //
        Double X;
        Double Y;
        //
        delta = N / DataCount;
        //
        // Fonksiyon
        //
        Stopwatch Time;
        Time = new Stopwatch();
        Time.Start();
        //
        for (Int32 b=0; b< M; b++) {

            for (Int32 i= 0; i < N; i++) {
            X = j * delta;
            Y = Offset + Gain * Math.Cos(X * Freq * Math.PI / 180.0);
            j = j + 1;
            }
        }
        //
        Time.Stop();
        Console.WriteLine("Elapsed time :{0}", Time.Elapsed);
    }

项目运行了3次,得到了延迟时间。

Visual Basic 项目运行时得到的结果;

Elapsed time :00:00:03.9066617
Elapsed time :00:00:03.9165436
Elapsed time :00:00:03.9031542

以及运行C#项目时得到的结果;

Elapsed time :00:00:02.4870551
Elapsed time :00:00:02.4931171
Elapsed time :00:00:02.5005793

同一框架下的不同结果。 vb.net 和 C# 之间的区别不止一秒。

为什么 vb.net 这么慢?

【问题讨论】:

  • 你在发行版中对此进行了测试吗,你是否使用了值得尊敬的基准测试工具
  • 您是否尝试重置您的电脑并以相反的顺序运行这些程序。我的意思是首先是 C#,然后是 VB.NET。衡量性能并不像围绕一个循环启动两个秒表那么简单。对了,你把这两个代码设置成release模式了吗?
  • 如果你想知道是否有区别,请检查生成的 IL 是否有两个代码 sn-ps。顺便说一句,您只需要一行即可创建并启动Stopwatch,即Dim time = Stopwatch.StartNew()
  • 尝试在 vb 项目的高级编译选项中启用未经检查的算术。生成的 IL 使用正在执行溢出检查的 .ovf 操作码。也可以将vb中的除法从/切换到\ ,后者执行整数除法,修改c#使其 not 整数除法(将一侧转换为双精度)或使用以下值至少对于整数/浮点除法的行为相同。在发布模式下编译,在 Visual Studio 外部运行,执行三个以上的测试(预热 jit 并丢弃一堆)并使用适当的基准框架
  • 感谢您的 cmets。正如 Pinkfloydx33 提到的,拆分过程存在问题。

标签: c# vb.net algorithm


【解决方案1】:

这两个代码在这一行有一个重要的区别:

delta = N / DataCount

在 VB 中,这是算术除法。在 C# 中,它是整数除法。
在 VB 中返回 0.00033333...,在 C# 中返回 0。

如果您修复 VB 代码也使用整数除法:

delta = N \ DataCount

两个代码开始显示完全相同的时间。

【讨论】:

  • 我也会检查 IL 代码。知道这很有趣,以前从未使用过 VB.net。
  • vb 也在生成溢出操作码 (.ovf)。在 VB 项目的高级编译选项中启用未经检查的算术应该可以解决这个问题并使它们更接近
  • 感谢 Gserg。您发现了一个被遗漏的重要错误。 pinkfloydx33 也提到了。在这两个项目中,当收到 delta = 0.000333 时,获得的时间非常接近。
【解决方案2】:

请检查生成的C#VB.Net 的IL 代码。在我的本地机器上,我观察到它们大致相同但并不相同。例如,在 VB.Net 中,它对算术加法、减法等进行了额外检查。VB.NET 使用诸如sub.ovfmul.ovf 之类的操作码,而 C# 则没有。我为这两种情况提供了 IL 输出。它们是使用发布模式编译的。您可以看到它们甚至从局部变量的数量开始有所不同。 VB 有 13 个局部变量,而 C# 有 11 个局部变量。

C#

 .method /*06000002*/ private hidebysig instance void 
    button1_Click(
      /*08000001*/ object sender, 
      /*08000002*/ class [mscorlib/*23000001*/]System.EventArgs/*01000014*/ e
    ) cil managed 
  {
    .maxstack 2
    .locals /*11000002*/ init (
      [0] int32 j,
      [1] float64 Offset,
      [2] float64 Gain,
      [3] float64 Freq,
      [4] int32 M,
      [5] int32 N,
      [6] float64 delta,
      [7] int32 DataCount,
      [8] float64 X,
      [9] class [System/*23000003*/]System.Diagnostics.Stopwatch/*01000015*/ Time,
      [10] int32 b,
      [11] int32 i
    )

    // [38 13 - 38 25]
    IL_0000: ldc.i4.0     
    IL_0001: stloc.0      // j

    // [40 13 - 40 32]
    IL_0002: ldc.r8       0.0
    IL_000b: stloc.1      // Offset

    // [41 13 - 41 30]
    IL_000c: ldc.r8       1
    IL_0015: stloc.2      // Gain

    // [42 13 - 42 30]
    IL_0016: ldc.r8       1
    IL_001f: stloc.3      // Freq

    // [43 13 - 43 28]
    IL_0020: ldc.i4       3000 // 0x00000bb8
    IL_0025: stloc.s      M

    // [44 13 - 44 29]
    IL_0027: ldc.i4       30000 // 0x00007530
    IL_002c: stloc.s      N

    // [45 13 - 45 30]
    IL_002e: ldc.r8       0.0
    IL_0037: stloc.s      delta

    // [46 13 - 46 37]
    IL_0039: ldloc.s      N
    IL_003b: ldloc.s      M
    IL_003d: mul          
    IL_003e: stloc.s      DataCount

    // [51 13 - 51 35]
    IL_0040: ldloc.s      N
    IL_0042: ldloc.s      DataCount
    IL_0044: div          
    IL_0045: conv.r8      
    IL_0046: stloc.s      delta

    // [56 13 - 56 36]
    IL_0048: newobj       instance void [System/*23000003*/]System.Diagnostics.Stopwatch/*01000015*/::.ctor()/*0A00001D*/
    IL_004d: stloc.s      Time

    // [57 13 - 57 26]
    IL_004f: ldloc.s      Time
    IL_0051: callvirt     instance void [System/*23000003*/]System.Diagnostics.Stopwatch/*01000015*/::Start()/*0A00001E*/

    // [59 18 - 59 29]
    IL_0056: ldc.i4.0     
    IL_0057: stloc.s      b

    IL_0059: br.s         IL_009b
    // start of loop, entry point: IL_009b

      // [62 22 - 62 33]
      IL_005b: ldc.i4.0     
      IL_005c: stloc.s      i

      IL_005e: br.s         IL_008f
      // start of loop, entry point: IL_008f

        // [64 21 - 64 35]
        IL_0060: ldloc.0      // j
        IL_0061: conv.r8      
        IL_0062: ldloc.s      delta
        IL_0064: mul          
        IL_0065: stloc.s      X

        // [65 21 - 65 78]
        IL_0067: ldloc.s      X
        IL_0069: ldloc.3      // Freq
        IL_006a: mul          
        IL_006b: ldc.r8       3.14159265358979
        IL_0074: mul          
        IL_0075: ldc.r8       180
        IL_007e: div          
        IL_007f: call         float64 [mscorlib/*23000001*/]System.Math/*01000024*/::Cos(float64)/*0A00001F*/
        IL_0084: pop          

        // [66 21 - 66 31]
        IL_0085: ldloc.0      // j
        IL_0086: ldc.i4.1     
        IL_0087: add          
        IL_0088: stloc.0      // j

        // [62 42 - 62 45]
        IL_0089: ldloc.s      i
        IL_008b: ldc.i4.1     
        IL_008c: add          
        IL_008d: stloc.s      i

        // [62 35 - 62 40]
        IL_008f: ldloc.s      i
        IL_0091: ldloc.s      N
        IL_0093: blt.s        IL_0060
      // end of loop

      // [59 38 - 59 41]
      IL_0095: ldloc.s      b
      IL_0097: ldc.i4.1     
      IL_0098: add          
      IL_0099: stloc.s      b

      // [59 31 - 59 36]
      IL_009b: ldloc.s      b
      IL_009d: ldloc.s      M
      IL_009f: blt.s        IL_005b
    // end of loop

    // [70 13 - 70 25]
    IL_00a1: ldloc.s      Time
    IL_00a3: callvirt     instance void [System/*23000003*/]System.Diagnostics.Stopwatch/*01000015*/::Stop()/*0A000020*/

    // [71 13 - 71 66]
    IL_00a8: ldstr        "Elapsed time :{0}"
    IL_00ad: ldloc.s      Time
    IL_00af: callvirt     instance valuetype [mscorlib/*23000001*/]System.TimeSpan/*01000025*/ [System/*23000003*/]System.Diagnostics.Stopwatch/*01000015*/::get_Elapsed()/*0A000021*/
    IL_00b4: box          [mscorlib/*23000001*/]System.TimeSpan/*01000025*/
    IL_00b9: call         void [mscorlib/*23000001*/]System.Console/*01000026*/::WriteLine(string, object)/*0A000022*/

    // [72 9 - 72 10]
    IL_00be: ret          

  } // end of method Form1::button1_Click

VB.NET

    .method /*06000014*/ private instance void 
        Button1_Click(
          /*08000005*/ object sender, 
          /*08000006*/ class [mscorlib/*23000001*/]System.EventArgs/*01000027*/ e
        ) cil managed 
      {
        .maxstack 2
        .locals /*11000002*/ init (
          [0] int32 j,
          [1] float64 Offset,
          [2] float64 Gain,
          [3] float64 Freq,
          [4] int32 M,
          [5] int32 N,
          [6] float64 delta,
          [7] int32 DataCount,
          [8] float64 X,
          [9] class [System/*23000002*/]System.Diagnostics.Stopwatch/*0100002C*/ Time,
          [10] int32 V_10,
          [11] int32 b,
          [12] int32 V_12,
          [13] int32 i
        )

        // [3 13 - 3 27]
        IL_0000: ldc.i4.0     
        IL_0001: stloc.0      // j

        // [5 13 - 5 34]
        IL_0002: ldc.r8       0.0
        IL_000b: stloc.1      // Offset

        // [6 13 - 6 32]
        IL_000c: ldc.r8       1
        IL_0015: stloc.2      // Gain

        // [7 13 - 7 32]
        IL_0016: ldc.r8       1
        IL_001f: stloc.3      // Freq

        // [8 13 - 8 30]
        IL_0020: ldc.i4       3000 // 0x00000bb8
        IL_0025: stloc.s      M

        // [9 13 - 9 31]
        IL_0027: ldc.i4       30000 // 0x00007530
        IL_002c: stloc.s      N

        // [10 13 - 10 32]
        IL_002e: ldc.r8       0.0
        IL_0037: stloc.s      delta

        // [11 13 - 11 39]
        IL_0039: ldloc.s      N
        IL_003b: ldloc.s      M
        IL_003d: mul.ovf      
        IL_003e: stloc.s      DataCount

        // [17 9 - 17 30]
        IL_0040: ldloc.s      N
        IL_0042: conv.r8      
        IL_0043: ldloc.s      DataCount
        IL_0045: conv.r8      
        IL_0046: div          
        IL_0047: stloc.s      delta

        // [22 9 - 22 29]
        IL_0049: newobj       instance void [System/*23000002*/]System.Diagnostics.Stopwatch/*0100002C*/::.ctor()/*0A000040*/
        IL_004e: stloc.s      Time

        // [23 9 - 23 21]
        IL_0050: ldloc.s      Time
        IL_0052: callvirt     instance void [System/*23000002*/]System.Diagnostics.Stopwatch/*0100002C*/::Start()/*0A000041*/

        // [25 9 - 25 36]
        IL_0057: ldloc.s      M
        IL_0059: ldc.i4.1     
        IL_005a: sub.ovf      
        IL_005b: stloc.s      V_10
        IL_005d: ldc.i4.0     
        IL_005e: stloc.s      b

        IL_0060: br.s         IL_00a8
        // start of loop, entry point: IL_00a8

          // [26 13 - 26 40]
          IL_0062: ldloc.s      N
          IL_0064: ldc.i4.1     
          IL_0065: sub.ovf      
          IL_0066: stloc.s      V_12
          IL_0068: ldc.i4.0     
          IL_0069: stloc.s      i

          IL_006b: br.s         IL_009c
          // start of loop, entry point: IL_009c

            // [27 17 - 27 30]
            IL_006d: ldloc.0      // j
            IL_006e: conv.r8      
            IL_006f: ldloc.s      delta
            IL_0071: mul          
            IL_0072: stloc.s      X

            // [28 17 - 28 73]
            IL_0074: ldloc.s      X
            IL_0076: ldloc.3      // Freq
            IL_0077: mul          
            IL_0078: ldc.r8       3.14159265358979
            IL_0081: mul          
            IL_0082: ldc.r8       180
            IL_008b: div          
            IL_008c: call         float64 [mscorlib/*23000001*/]System.Math/*01000038*/::Cos(float64)/*0A000042*/
            IL_0091: pop          

            // [29 17 - 29 26]
            IL_0092: ldloc.0      // j
            IL_0093: ldc.i4.1     
            IL_0094: add.ovf      
            IL_0095: stloc.0      // j

            // [30 13 - 30 17]
            IL_0096: ldloc.s      i
            IL_0098: ldc.i4.1     
            IL_0099: add.ovf      
            IL_009a: stloc.s      i

            IL_009c: ldloc.s      i
            IL_009e: ldloc.s      V_12
            IL_00a0: ble.s        IL_006d
          // end of loop

          // [31 9 - 31 15]
          IL_00a2: ldloc.s      b
          IL_00a4: ldc.i4.1     
          IL_00a5: add.ovf      
          IL_00a6: stloc.s      b

          IL_00a8: ldloc.s      b
          IL_00aa: ldloc.s      V_10
          IL_00ac: ble.s        IL_0062
        // end of loop

        // [33 9 - 33 20]
        IL_00ae: ldloc.s      Time
        IL_00b0: callvirt     instance void [System/*23000002*/]System.Diagnostics.Stopwatch/*0100002C*/::Stop()/*0A000043*/

        // [34 9 - 34 61]
        IL_00b5: ldstr        "Elapsed time :{0}"
        IL_00ba: ldloc.s      Time
        IL_00bc: callvirt     instance valuetype [mscorlib/*23000001*/]System.TimeSpan/*01000039*/ [System/*23000002*/]System.Diagnostics.Stopwatch/*0100002C*/::get_Elapsed()/*0A000044*/
        IL_00c1: box          [mscorlib/*23000001*/]System.TimeSpan/*01000039*/
        IL_00c6: call         void [mscorlib/*23000001*/]System.Console/*0100003A*/::WriteLine(string, object)/*0A000045*/

        // [35 5 - 35 12]
        IL_00cb: ret          

      } // end of method Form1::Button1_Click

【讨论】:

  • 仅供参考,您当地人的人数是 1(s/b 14 和 12),但我怀疑人数是否很重要,这两个临时演员被用作临时演员.. .虽然它确实强调了两者是不同的
  • @pinkfloydx33,是的,这就是我在回答中写的当地人不同
  • 我的意思是,你没算对。你有一个“off by one”错误(基于 0 的索引)
  • @pinkfloydx33,哦,是的,你是对的!在忙碌的一天工作后试图回答的副作用。我会修复它们
猜你喜欢
  • 2015-09-09
  • 2013-05-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
相关资源
最近更新 更多