为什么C#执行Math.Sqrt()比VB.NET更慢?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)

背景

在今天上午进行基准测试时,我和我的同事发现了一些有关C#代码与VB.NET代码性能的奇怪事情。

我们开始比较C#和Delphi Prism计算素数,发现Prism快了大约30%。在生成IL时,我认为CodeGear优化的代码更多(它exe大约是C#的两倍,并且具有各种不同的IL)。

我决定在VB.NET中编写一个测试,假设微软的编译器最终会为每种语言编写基本相同的IL。但是,结果更令人震惊:在C#上代码运行速度比VB运行速度慢3倍以上!

生成的IL是不同的,但并非如此,我不太了解它的差异。

基准

我已经在下面列出了每个代码。在我的机器上,VB在6.36秒内找到了348513个素数。C#在21.76秒内找到相同数量的素数。

计算机规格和笔记

  • 英特尔酷睿2四核6600 @ 2.4Ghz

我在那里测试过的每台机器在C#和VB.NET之间的基准测试结果中都有明显的差异。

这两个控制台应用程序都是在发布模式下编译的,否则没有项目设置从Visual Studio 2008生成的默认设置中更改。

VB.NET代码

Imports System.Diagnostics

Module Module1

    Private temp As List(Of Int32)
    Private sw As Stopwatch
    Private totalSeconds As Double

    Sub Main()
        serialCalc()
    End Sub

    Private Sub serialCalc()
        temp = New List(Of Int32)()
        sw = Stopwatch.StartNew()
        For i As Int32 = 2 To 5000000
            testIfPrimeSerial(i)
        Next
        sw.Stop()
        totalSeconds = sw.Elapsed.TotalSeconds
        Console.WriteLine(String.Format("{0} seconds elapsed.", totalSeconds))
        Console.WriteLine(String.Format("{0} primes found.", temp.Count))
        Console.ReadKey()
    End Sub

    Private Sub testIfPrimeSerial(ByVal suspectPrime As Int32)
        For i As Int32 = 2 To Math.Sqrt(suspectPrime)
            If (suspectPrime Mod i = 0) Then
                Exit Sub
            End If
        Next
        temp.Add(suspectPrime)
    End Sub

End Module

C#代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace FindPrimesCSharp {
    class Program {
        List<Int32> temp = new List<Int32>();
        Stopwatch sw;
        double totalSeconds;


        static void Main(string[] args) {

            new Program().serialCalc();

        }


        private void serialCalc() {
            temp = new List<Int32>();
            sw = Stopwatch.StartNew();
            for (Int32 i = 2; i <= 5000000; i++) {
                testIfPrimeSerial(i);
            }
            sw.Stop();
            totalSeconds = sw.Elapsed.TotalSeconds;
            Console.WriteLine(string.Format("{0} seconds elapsed.", totalSeconds));
            Console.WriteLine(string.Format("{0} primes found.", temp.Count));
            Console.ReadKey();
        }

        private void testIfPrimeSerial(Int32 suspectPrime) {
            for (Int32 i = 2; i <= Math.Sqrt(suspectPrime); i++) {
                if (suspectPrime % i == 0)
                    return;
            }
            temp.Add(suspectPrime);
        }

    }
}

为什么C#的执行Math.Sqrt()速度比VB.NET慢?

提问于
用户回答回答于

C#实现Math.Sqrt(suspectPrime)每次都通过循环重新计算,而VB只在循环开始时计算它。这仅仅是由于控制结构的性质。在C#中,for这只是一个奇特的while循环,而在VB中则是一个独立的构造。

使用这个循环会提高分数:

        Int32 sqrt = (int)Math.Sqrt(suspectPrime)
        for (Int32 i = 2; i <= sqrt; i++) { 
            if (suspectPrime % i == 0) 
                return; 
        }
用户回答回答于

我同意C#代码在每次迭代中计算sqrt的声明,这里直接证明了Reflector:

VB版本:

private static void testIfPrimeSerial(int suspectPrime)
{
    int VB$t_i4$L0 = (int) Math.Round(Math.Sqrt((double) suspectPrime));
    for (int i = 2; i <= VB$t_i4$L0; i++)
    {
        if ((suspectPrime % i) == 0)
        {
            return;
        }
    }
    temp.Add(suspectPrime);
}

C#版本:

 private void testIfPrimeSerial(int suspectPrime)
{
    for (int i = 2; i <= Math.Sqrt((double) suspectPrime); i++)
    {
        if ((suspectPrime % i) == 0)
        {
            return;
        }
    }
    this.temp.Add(suspectPrime);
}

哪一点可以指向VB生成的代码,即使开发人员天真得足以在循环定义中调用sqrt,它的表现也会更好。

扫码关注云+社区