[八卦] 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的模板递归也算是其亮点之一,^_^
Global site tag (gtag.js) - Google Analytics