Golang效能測試與思考
本文測試Go、Python、PyPy、C的效率,作為學習Go的參考標準。測試用例:進行(2<<25)次簡單加法
測試環境: 系統:Windows7 專業版 CPU:Intel® Core™ i5-4590 CPU @ 3.30GHZ 3.30GHZ, 14級流水線(Pipeline)
測試用例:進行(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<stdlib.h> #include "test1.h" #include<stdio.h> #include<time.h> #ifdef _WIN32 #include <Windows.h> #include <sys/timeb.h> #elif defined __linux__ #include <time.h> #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;i++) { j += 1; } unsigned long end = Clock(); printf("N:%I64d, time:%dms\n", N, end-start); return 0; }
測試結果: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的極限,著實是一門高效的編譯型語言。