Golang性能测试与思考

本文测试Go、Python、PyPy、C的效率,作为学习Go的参考标准。测试用例:进行(2<<25)次简单加法

测试环境:

系统:Windows7 专业版

CPU:Intel® Core™ i5-4590 CPU @ 3.30GHZ 3.30GHZ, 14级流水线(Pipeline)

参考资料:
Core微架构14级流水线

测试用例:进行(2<<25)次简单加法

// golang example
package main

import "fmt"
import "time"

func main() {
    var N int = 2 << 25
    var j int = 0

    t0 := time.Now()

    for i := 1; i < (N); i++ {
        j += 1
    }

    elapsed := time.Since(t0)
    fmt.Println("N:", N, "time:", elapsed)
}

测试结果:N: 67108864 time: 20.5027ms

# -*- coding: utf-8 -*-
# Python and Pypy example

import time

t0 = time.clock()

N = 2 << 25
j = 0

for i in xrange(N):
    j += 1

print "N:{}, time:{:.2f}ms".format(N, (time.clock() - t0) * 1000)

测试结果:

Python N:67108864, time:5102.14ms

PyPy: N:67108864, time:124.16ms

#include "stdafx.h"
#include
#include "test1.h"

#include
#include


#ifdef _WIN32
#include 
#include 
#elif defined __linux__
#include 
#endif

 unsigned long ClockMs64()
{
#ifdef _WIN32
    struct __timeb64 timebuffer;
    _ftime64_s(&timebuffer);
    return timebuffer.time * 1000 + timebuffer.millitm;

#else
    timespec ts;
    if (-1 == clock_gettime(CLOCK_REALTIME, &ts))
    {
        return 0;
    }
    return ((unsigned long)ts.tv_sec) * 1000 + ts.tv_nsec/1000000;
#endif
}

 unsigned long Clock()
{
    return (unsigned long)ClockMs64();
}

int _tmain(int argc, _TCHAR* argv[])
{
    UINT64 N =  2 << 25;
    UINT64 j = 1;
    unsigned long start = Clock();

    for(UINT64 i=0;i

测试结果:N:67108864, time:160ms

综合以上测试结果:

时间
C 160ms
PyPy 124.16ms
Python 5102.14ms
Golang 20.50ms

结论:从测试结果来看,执行效率Golang > PyPy > C > Python

分析:

Golang是编译型语言,会将代码编译成二进制可执行机器码。我们来分析执行Golang的执行时间,我们知道一个汇编指令至少执行一个CPU周期(指令执行整数个周期,大部分指令执行一个周期,指令具体执行周期可以参考CPU手册)。也就是说只要我们知道执行整个程序的汇编指令数量,我们就能对程序运行时间做出评判。

测试用例循环体内执行以下操作,大致翻译成汇编指令,统计汇编指令数目
1. i < N --> 将i、N入栈,cmp后比较结果来做Jmp操作,大约5条汇编指令;
2. j += 1 --> 将j入栈,执行Inc操作,然后保存到j,大约3条汇编指令;
3. i ++ --> 将i入栈,执行Inc,保存到i,大约3条汇编;
4. 还有一个隐藏的Jump到操作1的操作, 1条汇编

故一个循环体总体汇编指令条目为(5+3+3+1)=12条

CPU主频为3.30GHZ,循环体汇编条目约为12条。我们以CPU满载、每条指令一个周期计算,执行2<<25次循环体需要用时=1000 * ((2<<25) * 12) / (3.3 * (10**9)) = 244.03ms。
而我们测试Golang用时20.50ms,为什么Golang比前面计算的244.03ms远远要小?秘密在于CPU的指令流水线,根据资料我们知道Intel CPU是14级流水线架构,也就是说一个CPU周期最大可执行14条汇编指令。我们用单级流水线理论时间除以Golang用时:244.03ms / 20.50ms = 11.9,考虑多CPU周期汇编指令的存在和系统调度消耗,14是我们理论上限值,可见结果符合预期。

Golang在这个测试用例中比C语言更快,更是秒杀Python,超乎预期。通过计算发现Golang的计算效率接近CPU的极限,着实是一门高效的编译型语言。

另外,附上常见的Benchmark连接The Computer Language
Benchmarks Game,可对比各种语言的性能情况

参考资料:

Core微架构-14级流水线

个人主页: http://liangiter.top

你可能感兴趣的:(编程,IT,Go,Golang)