[八卦] D语言的性能不一定比Java强
fxsjy
2007-11-30
public class Main { private static int fib(int n){ if(n==0 || n==1) return 1; else{ return fib(n-1)+fib(n-2); } } public static void main(String[] args){ for(int i=0;i<=35;i++){ System.out.printf("n=%d => %d\n",i,fib(i)); } } } int fib(int n){ if(n==0 || n==1) return 1; else{ return fib(n-1)+fib(n-2); } } void main(string[] args){ for(int i=0;i<=35;i++){ printf("n=%d => %d\n",i,fib(i)); } } 没有量化运行时间,但是肉眼可以看出来Java跑得快。 而且java编译没有优化,D用的是2.008,加了-O -release |
|
oldrev
2007-11-30
毫无价值的测试,程序大部分时间花在 IO 上,跟速度有什么关系。
|
|
Colorful
2007-12-01
性能测试不能从某一点上来说明问题,应该综合全面的看待语言的性能表现。
暂且不论程序设计问题,楼主的程序实例的主要运行开销在实现递归的活动记录栈调用上,在I/O的开销很小。这可以通过以下示例来证明: BTW,我说怎么看着别扭呢,楼主的斐波那契数算法有错啊。 int fib(int n) { if(n==0 || n==1) return n; else { return fib(n-1)+fib(n-2); } } void main() { for(int i=0;i<=35;i++) { uint i = fib(i); } } 上述程序花费的时间跟楼主的示例相差无几(这说明I/0开销不是主要部分)。由于我的机器上没有Java环境,暂时用C#环境代替,我相信这两个语言性能还是很相近的,甚至C#的性能要更好一些。在Windows XP SP2 + AMD 1700+上,采用 QueryPerformanceFrequency() 函数 + Release 模式下测试,两种语言花费的大概时间如下(多次测试取均值,时间单位为Tick): C# -> 960 ~ 1000 D -> 4100000 ~ 4200000 从结果来看,相差了好几个数量级,说明D语言编译器对于递归的优化很差,同时提升的空间也很大,:-)。 对于楼主的特定测试示例,偶给个D语言模板递归,性能绝对要比Java/C#之流强N倍,因为是编译期就计算出值来,所以没法不快,就是循环的时候不能用变量,:-)。 template fib(int n : 1) { enum{ fib = 1 } } template fib(int n : 0) { enum{ fib = 0 } } template fib(int n) { enum{ fib = fib!(n-1) + fib!(n-2) } } void main() { for(int i = 0; i <= 35; i++) { size_t j = fibTemplate!(35); } } 它在偶的机器上速度实在是快,只花费了4 ticks。 PS:斐波那契数的算法我记得有非递归的算法来着,可惜已经忘光了,哈哈。好在只是测试性能,不是考算法。 |
|
redsea
2007-12-01
简单的数值测试, 无法区分这些语言的速度. 而且这对语言的内存模型, 对象创建析构开销等完全没有评价到.
类似的简单测试, Java 在不少测试的速度已经能够超过了c/c++, 为什么现在不说 Java 是最快的语言 ? 复杂度, 最低至少也要做到 language shootout 那里的复杂度. language shootout 那边的大多数测试, 仍然没有对对语言的内存模型, 对象创建析构开销有测试. 在那里, Java server 有三项测试的速度比 gcc 快. |
|
redsea
2007-12-01
才递归35层, 搞不好启动时间比真正执行时间要长很多呢.
queryperformancecount 是在本程序内部的吧 ? 不是在外部用一个程序来测试吧? 否则这测试程序的启动时间, 还会受到有没有装防病毒软件之类的影响. Colorful 写道 性能测试不能从某一点上来说明问题,应该综合全面的看待语言的性能表现。
暂且不论程序设计问题,楼主的程序实例的主要运行开销在实现递归的活动记录栈调用上,在I/O的开销很小。这可以通过以下示例来证明: BTW,我说怎么看着别扭呢,楼主的斐波那契数算法有错啊。 int fib(int n) { if(n==0 || n==1) return n; else { return fib(n-1)+fib(n-2); } } void main() { for(int i=0;i<=35;i++) { uint i = fib(i); } } 它在偶的机器上速度实在是快,只花费了4 ticks。 PS:斐波那契数的算法我记得有非递归的算法来着,可惜已经忘光了,哈哈。好在只是测试性能,不是考算法。 |
|
hurd
2007-12-01
编译器发展阶段不考虑那么多优化也许比较好。
应用时优化的工作可以交给llvm等来做。 |
|
qiezi
2007-12-01
Colorful 写道 int fib(int n) { if(n==0 || n==1) return n; else { return fib(n-1)+fib(n-2); } } void main() { for(int i=0;i<=35;i++) { uint i = fib(i); } } 上述程序花费的时间跟楼主的示例相差无几(这说明I/0开销不是主要部分)。由于我的机器上没有Java环境,暂时用C#环境代替,我相信这两个语言性能还是很相近的,甚至C#的性能要更好一些。在Windows XP SP2 + AMD 1700+上,采用 QueryPerformanceFrequency() 函数 + Release 模式下测试,两种语言花费的大概时间如下(多次测试取均值,时间单位为Tick): C# -> 960 ~ 1000 D -> 4100000 ~ 4200000 从结果来看,相差了好几个数量级,说明D语言编译器对于递归的优化很差,同时提升的空间也很大,:-)。 如果测试程序真是你这写的这样,明显你的测试程序测试的是编译器对于uint i = fib(i)这种代码的消除能力,跟递归无关。因为这种不影响程序运行结果的代码是可以优化消除的,结果只剩下个空循环,很多C++编译器也有这种优化能力,VC的release编译模式就会自动优化这个。DMD显然没能达到预期。 |
|
qiezi
2007-12-01
fib我以前做过测试,测试环境是linux。使用gdc编译比DMD快了近一倍,比java明显是要快的,但java比dmd编译的的确是要好一些。
当时测试的dmd/java/gdc/gcc耗时大概是2.8:1.7:1.2:1.2,后来对DMD编译选项以及测试程序做过一些修改,最终可以优化到1.7:1.7:1.2:1.2,具体怎么做的记不清了,这种东西都是编译器实现的问题,跟语言关系不大。 |
|
tomqyp
2007-12-01
原来GDC还有性能方面优势
|
|
Colorful
2007-12-01
上次的测试把时间单位搞错了,所以出现了很“惨”的答案,呵呵,这一次重新把完整的测试代码给贴上。
另外,qiezi提到了VC的优化问题(该问题在C#和DMD中不会出现),为了避免该问题,修正了测试代码。 测试平台 Windows XP SP2 + AMD 1700+ 时间单位 毫秒 因为机器上没有C/C++环境,所以安装了VC 2008和GCC的Win移植MinGW。 C/C++代码 #include <iostream> #include "Windows.h" using namespace std; int fib(int n) { if(n==0 || n==1) return n; else { return fib(n-1)+fib(n-2); } } int main() { int arr[36]; LARGE_INTEGER li; if(QueryPerformanceFrequency(&li)) { QueryPerformanceCounter(&li); long long j = li.QuadPart; for(int i=0;i<=35;i++) { arr[i] = fib(i); } QueryPerformanceCounter(&li); long long k = li.QuadPart; for(int i = 0; i <= 35; i++) { cout << arr[i] << '\n'; } cout << '\n'; cout << (k-j) / 10000 << '\n'; } else { unsigned int j = GetTickCount(); for(int i=0;i<=35;i++) { arr[i] = fib(i); } unsigned int k = GetTickCount(); for(int i = 0; i <= 35; i++) { cout << arr[i] << '\n'; } cout << '\n'; cout << (k-j) << '\n'; } return 0; } VC 2008下花费的时间为550 ~ 565 MinGW(即GCC 3.4.5)时间为360 ~ 370 C#测试代码 using System; using System.Diagnostics; namespace Colorful.CSharp.Sample { class Program { static void Main(string[] args) { int[] arr = new int[36]; Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i <= 35; i++) { arr[i] = fib(i); } watch.Stop(); for (int i = 0; i <= 35; i++) { Console.WriteLine(arr[i]); } Console.WriteLine(); Console.WriteLine(watch.ElapsedMilliseconds); } static int fib(int n) { if (n == 0 || n == 1) return n; else { return fib(n - 1) + fib(n - 2); } } } .NET 3.5下花费时间为960 ~ 980 C#花费的时间是VC 2008的2倍,MinGW的3倍左右。 接下来是D测试代码 import std.stdio; import std.c.windows.windows; int fib(int n){ if(n==0 || n==1) return n; else{ return fib(n-1)+fib(n-2); } } void main() { int[36] arr; long li; if(QueryPerformanceFrequency(&li)) { QueryPerformanceCounter(&li); long j = li; for(int i=0;i<=35;i++) { arr[i] = fib(i); } QueryPerformanceCounter(&li); long k = li; for(int i = 0; i <= 35; i++) { writefln(arr[i]); } writefln(); writefln((k-j) / 10000); } else { uint j = GetTickCount(); for(int i=0;i<=35;i++) { arr[i] = fib(i); } uint k = GetTickCount(); for(int i = 0; i <= 35; i++) { writefln(arr[i]); } writefln(); writefln((k-j)); } } DMD 2.008下花费时间为410 ~ 418 D比起C/C++大概是MinGW的1.1倍,VC 2008的0.75倍,C#的0.43倍左右。 答案已经很明显了。此外,D的模板递归也算是其亮点之一,^_^ |