3

我一直在比较三种主要语言之间的原始 CPU 性能速度(代码和结果如下)。我很好奇主要语言如何比较原始计算能力。我有一个理论认为,在不涉及内存开销的情况下,Java 和 C# 可能会与 C++ 相媲美。

我的问题:

1) 编辑(C++ 时序现在更现实)

2)我认为JVM在第一次迭代中花费了很长时间,但是第二次它已经完成了分析并因此进行了优化,这是否正确?Hotspot 怎么知道在我的外部循环的第一次迭代之后完成优化而不是进行到一半?

3) 为什么 C# 不像 Java 那样执行并且一开始就进行了大量优化?C# 与 Java 有什么不同?为什么 C# 速度较慢 - 仅仅是因为优化较少?

4) C# 测试时序在 2246 和 2262 毫秒之间振荡是否有任何具体原因,这可能是两个不同的时间,因为 CPU 有两个内核?

编辑:更新代码以显示 C# 代码中的秒表用法。

编辑:更正 C++ 时序代码和结果

设置:

  • C++:VS2010 和 Intel 编译器(内置发布模式,优化:O2,启用内在函数:是,偏爱大小和速度:不支持,省略帧指针:否,启用光纤安全优化:否,整个程序优化:是)

  • Java:Eclipse、Hotspot 64 位编译器版本 17、Java 1.6

  • C#:VS2010 和 .net 4.0(内置发布模式)

  • CPU:Intel E6600 (2.4GHz),运行频率为 2.7GHz,总线速度 300MHz,8GB 内存,DRAM 频率:375MHz

  • 赢 7(64 位)

C++ 代码:

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <fstream> 

using namespace std;


double PCFreq = 0.0;
__int64 CounterStart = 0;

void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = li.QuadPart;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

static long counter = 0;

int _tmain(int argc, _TCHAR* argv[])
{

    for (int m = 0; m < 10; m++)
    {
        StartCounter();
        counter = 0;

        for (int j = 0; j < 3; j++)
        {
            //Just to test timing is working correctly
            //int* p = new int;

            for (long i = 0; i < 200000000; i++)
            {
                counter++;
            }
        }

        cout << GetCounter()*1000000 << " microseconds" << endl;
    }


    int p = 0;
    cin >> p;
    return 0;
}

C++ 结果:

7.19 微秒

1.89

2.27

1.51

4.92

10.22

10.22

9.84

9.84

10.6

Java代码:

public class main {

    static long counter = 0;

    public static void main(String[] args) {

        for(int m=0; m<10; m++){
            long start = System.nanoTime();
            counter = 0;

            for(int j=0;j<3; j++){
                for(long i=0; i<200000000; i++){
                    counter++;
                }
            }

            System.out.println(((System.nanoTime()-start)/1000000) + " ms");
        }
    }
}

Java结果:

5703 milliseconds
471 ms
468 ms
467 ms
469 ms
467 ms
467 ms
467 ms
469 ms
464 ms

C#代码:

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

namespace t1
{
    class Program
    {
        static long counter = 0;

        static void Main(string[] args)
        {
            for (int m = 0; m < 10; m++)
            {
                Stopwatch s = new Stopwatch();
                s.Start();
                counter = 0;

                for (int j = 0; j < 3; j++)
                {

                    for (long i = 0; i < 200000000; i++)
                    {
                        counter++;
                    }

                }
                s.Stop();
                Console.WriteLine(s.Elapsed.TotalMilliseconds + " ms");
            }

            Console.ReadLine();
        }
    }
}

C# 结果:

2277 毫秒

2246 毫秒

2262 毫秒

2246 毫秒

2262 毫秒

2246 毫秒

2262 毫秒

2246 毫秒

2262 毫秒

2262 毫秒

4

4 回答 4

2

您的 C++ 代码中有一个逻辑问题,它使用QueryPerformanceFrequency

PCFreq = double(li.QuadPart)/1000000000.0; // <- this is not correct
PCFreq = li.QuadPart;                      // <- this is correct

您应该在打印代码中分配li.QuadPartPCFreq转换为毫秒或纳秒:

// convert from seconds to milliseconds
cout << GetCounter() * 1000.0 << endl;

通过此更改,我可以获得 C++ 代码的实际时间。无论这些时间是否“有效”或在进行比较时是否有用,我都不会发表评论。

于 2012-04-21T15:20:40.513 回答
2

1 - Sixlettervariables 似乎已经指出了你在这个问题上的错误

2 - 热点将优化代码。这是一个类似的问题,它也看到循环加速了 10 倍。所以你看到的是预期的输出。 第一次 Java 循环运行缓慢,为什么?[太阳热点 1.5,sparc]

3 - 我对 C# 的了解不够,无法提供帮助。它可能没有优化内部循环(你有 3 个不同的循环)。也许尝试将您正在测试的 2 个循环提取到一个完全独立的方法中,看看是否有帮助。

4 - DateTime 是表示日期和时间,而不是高精度计时。因此,它不是那么准确。据我所知,DateTime.Now 的分辨率为 10 毫秒

(仅供参考,这篇文章对 JIT、C# 和 C++ 优化有一些很好的解释,可能会对您有所帮助:C++ 性能与 Java/C#

于 2012-04-21T15:32:29.500 回答
1

我认为编译器可能会在编译时计算计数器的值并且不会遍历您的循环。

我认为一个简单的计数器是一个非常糟糕的基准。

顺便说一句,尝试在方法中运行 java 代码。由于 JIT 优化,它可能会更快。(但我不确定)

于 2012-04-21T14:58:59.603 回答
1

各种编译器的基准测试已经完成并很好地组合在一起。

计算机语言基准游戏

Java 7 服务器与 GNU C++

C# Mono 与 GNU C++

C# Mono 与 Java 7 服务器

虽然 Java 7 Server 比 C# Mono 2.10.8 更快,但请查看 Java 7 使用的内存量。

于 2012-04-21T15:45:09.487 回答