【发布时间】:2012-05-02 20:28:35
【问题描述】:
我一直在比较三种主要语言之间的原始 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
- Win 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 毫秒
【问题讨论】:
-
对于 C++ 版本,请检查编译器的程序集输出。循环可以完全优化。
-
您不需要一个出色的编译器来恒定折叠该循环,I 可以编写一个这样做的通道(对于原始类型)。我想 JVM/CLR JIT 不做同样事情的唯一原因是您的 Java/C# 基准测试存在问题(JIT 甚至会启动吗?)。
-
对于 C#,您是在 Visual Studio 中运行还是在外部运行?在附加调试器的情况下运行会禁用大多数优化。仅在发布模式下构建是不够的。
-
@user1291492 我不确定您建议使用什么基准。我同意这样的微基准对大多数应用程序来说是无用的——但是,这适用于所有微基准,无论是否多线程。在微基准测试有用的情况下,应用程序可能仍然会在各个内核上进行大量列出,无论并行使用多少内核。当您使用 N 个内核时,知道在一个内核上处理数字的速度有多快仍然有一些好处。当然,在这两种情况下,您都需要知道实际计算了多长时间,而不是等待 I/O 或锁定。
-
DateTime.Now对于在该级别测量时间没有用处。您正在寻找Stopwatch。此外,您似乎没有正确使用 QueryPerformanceCounter。(stop-start)/freq= 秒。
标签: c# java c++ performance caching