It has been around a year since he started to work with golang. He has been studying it for himself in his spare time, but he is still mainly limited to grammar and language features. He hasn't used it to write practical projects yet.
There are many resources on the Internet to learn about golang syntax and language features. Later, I may write a rough article to compare the features of golang, C ++, Delphi, and even C.
I am an acute person (of course, it's better now), so as a code farmer, I am obviously sensitive to "efficiency. The efficiency here refers not only to the degree of optimization of the machine code generated by the compiler, but also to the compilation speed of the compiler. Therefore, I am not very interested in C ++, although it is my usual working language.
Let's get down to the truth.
We use golang, C ++, and Delphi to write four small examples, including common application scenarios and strings) operations and data-intensive computing (of course, database function optimization will also be involved ). My computer software and hardware environment: win7 64bit, Xeon E3-1230 (8-core), 16g RAM. Golang versions are 1.3.1 Windows/386, VC uses vs 2012, and Delphi uses xe6 update1. The VC and Delphi compilation settings are Win32 & release, and golang uses the default configuration.
The first is the example of calculating π. The Code is as follows.
Golang:
package main
import (
"fmt"
"time"
)
const cNumMax = 999999999
func main() {
sign := 1.0
pi := 0.0
t1 := time.Now()
for i := 1; i < cNumMax+2; i += 2 {
pi += (1.0 / float64(i)) * sign
sign = -sign
}
pi *= 4
t2 := time.Now()
fmt.Printf("PI = %f; Time = %d\n", pi, t2.Sub(t1)/time.Millisecond)
}
C++:
#include "stdafx.h"#include <stdio.h>#include <time.h>int _tmain(int argc, _TCHAR* argv[]){ const int cNumMax = 999999999;double sign = 1.0; double pi = 0; clock_t t1 = clock(); for (int i = 1; i < cNumMax + 2; i += 2) { pi += (1.0f / (double)i) * sign; sign = -sign; } pi *= 4; clock_t t2 = clock(); printf("PI = %lf; Time = %d\n", pi, t2 - t1); return 0;}
Delphi:
program PiCalcer;{$APPTYPE CONSOLE}{$R *.res}uses System.SysUtils, System.DateUtils;const cNumMax = 999999999;var Sign: Double = 1.0; Pi : Double = 0.0; I : Integer; T1 : Double; T2 : Double; S : string;begin T1 := Now; I := 1; while I < cNumMax + 2 do begin Pi := Pi + (1.0 / I) * Sign; Sign := -Sign; I := I + 2; end; Pi := Pi * 4; T2 := Now; S := Format(‘PI = %.6f; Time = %d‘, [Pi, MilliSecondsBetween(T2, T1)]); Writeln(S); Readln;end.
Execute 10 times, and the result is as follows (unit: milliseconds ):
Golang: 2038 2028 2036 2024 2034 2015 2034 2018 2024 2018, average: 2026.9;
C ++: 2041 2052 2062 2036 2033 2049 2039 2026 2037 2038, average: 2041.3;
Delphi: 2594 2572 2574 2584 2574 2564 2575 2575 2571 2563, average: 2574.6.
The result is really good, and it is faster than VC, But Delphi, everyone understands, optimization has never been its "strength ".
Then there is a prime number generation example.
Golang:
package main
import (
"fmt"
"time"
)
const cNumMax = 10000000
func main() {
t1 := time.Now()
var nums [cNumMax + 1]int
var i, j int
for i = 2; i < cNumMax+1; i++ {
nums[i] = i
}
for i = 2; i < cNumMax+1; i++ {
j = 2
for j*i < cNumMax+1 {
nums[j*i] = 0
j++
}
}
cnt := 0
for i = 2; i < cNumMax+1; i++ {
if nums[i] != 0 {
cnt++
}
}
t2 := time.Now()
fmt.Println("Time:", t2.Sub(t1), " Count:", cnt)
}
C++:
#include "stdafx.h"#include <stdlib.h>#include <time.h>const int cNumMax = 10000000;int _tmain(int argc, _TCHAR* argv[]){ clock_t t1 = clock(); int *nums = (int*)malloc(sizeof(int) * (cNumMax + 1)); int i; for (i = 2; i < cNumMax + 1; i++) { nums[i] = i; } int j; for (i = 2; i < cNumMax + 1; i++) { j = 2; while (j * i < cNumMax + 1) { nums[j * i] = 0; j++; } } int cnt = 0; for (i = 2; i < cNumMax + 1; i++) { if (nums[i] != 0) { cnt++; } } free(nums); clock_t t2 = clock(); printf("Time: %dms; Count: %d\n", t2 - t1, cnt);}
Delphi:
program PrimeSieve;{$APPTYPE CONSOLE}{$R *.res}uses System.SysUtils, System.DateUtils;const cNumMax = 10000000;var T1, T2: Double; I, J : Integer; Cnt : Integer; Nums : array of Integer;begin T1 := Now; SetLength(Nums, cNumMax + 1); for I := 2 to cNumMax do Nums[I] := I; for I := 2 to cNumMax do begin J := 2; while J * I < cNumMax + 1 do begin Nums[J * I] := 0; Inc(J); end; end; Cnt := 0; for I := 2 to cNumMax do begin if Nums[I] <> 0 then Inc(Cnt); end; SetLength(Nums, 0); T2 := Now; Writeln(Format(‘Cnt = %d; Time = %d‘, [Cnt, MilliSecondsBetween(T2, T1)])); Readln;end.
Execute the command 10 times, and the result is as follows (unit: milliseconds ):
Golang: 959 957 959 953 961 951 948 956 956 956, average: 955.6;
C ++: 965 965 967 953 961 964 963 960 956 956, average: 961;
Delphi: 973 976 973 982 981 970 977 979 971 977, average: 975.9;
Still, golang looks the fastest, while Delphi is normally at the end.
So I can't help but want to come up with an example that shows the advantages of Delphi. There is almost no doubt that this example is related to string operations (and Memory Manager, therefore, there is an example of String concatenation (which involves function calls such as inttostr/ITOA, And I have implemented C ++ inttostr ).
Golang:
package main
import (
"bytes"
"fmt"
"strconv"
"time"
)
const cNumMax = 1000000
// bytes.Buffer(7.2.6)
func testViaBuffer() string {
var buf bytes.Buffer
for i := 0; i < cNumMax; i++ {
buf.WriteString(strconv.Itoa(i))
}
return buf.String()
}
// +=
func testViaNormal() string {
var ret string
for i := 0; i < cNumMax; i++ {
ret += strconv.Itoa(i)
}
return ret
}
func main() {
fmt.Println("Test via bytes.Buffer...")
t1 := time.Now()
s := testViaBuffer()
t2 := time.Now()
fmt.Printf("Result: %s...(Length = %d); Time: %dms\n\n", s[2000:2005], len(s), t2.Sub(t1)/time.Millisecond)
fmt.Println("Test via normal way...")
t1 = time.Now()
s = testViaNormal()
t2 = time.Now()
fmt.Printf("Result: %s...(Length = %d); Time: %dms\n", s[2000:2005], len(s), t2.Sub(t1)/time.Millisecond)
}
C++:
#include "stdafx.h"#include <time.h>#include <stdarg.h>#include <string>#include <iostream>using namespace std;const int cNumMax = 1000000;wstring FormatV(const wchar_t* pwcFormat, va_list argList){ wstring ws; int nLen = _vscwprintf(pwcFormat, argList); if (nLen > 0) { ws.resize(nLen); vswprintf_s(&ws[0], nLen + 1, pwcFormat, argList); } return ws;}wstring __cdecl Format(const wchar_t* pwcFormat, ...){ va_list argList; va_start(argList, pwcFormat); wstring ws = FormatV(pwcFormat, argList); va_end(argList); return ws;}string FormatVA(const char* pcFormat, va_list argList){ string s; int nLen = _vscprintf(pcFormat, argList); if (nLen > 0) { s.resize(nLen); vsprintf_s(&s[0], nLen + 1, pcFormat, argList); } return s;}string __cdecl FormatA(const char* pcFormat, ...){ va_list argList; va_start(argList, pcFormat); string s = FormatVA(pcFormat, argList); va_end(argList); return s;}wstring IntToStr(int nValue){ return Format(L"%d", nValue);}string IntToStrA(int nValue){ return FormatA("%d", nValue);}wstring testW(){ wstring ret = L""; for (int i = 0; i < cNumMax; i++) { ret += IntToStr(i); } return ret;}string test(){ string ret = ""; for (int i = 0; i < cNumMax; i++) { ret += IntToStrA(i); } return ret;}int _tmain(int argc, _TCHAR* argv[]){ cout << "Starting test with a loop num of " << cNumMax << endl; clock_t t1 = clock(); string s = test(); clock_t t2 = clock(); cout << "Result: " << s.substr(2000, 5) << "..." << "; Size: " << s.size() << "; Time: " << t2 - t1 << "ms" << endl; cout << endl; cout << "Starting test for WSTRING with a loop num of " << cNumMax << endl; t1 = clock(); wstring ws = testW(); t2 = clock(); wcout << "Result: " << ws.substr(2000, 5) << "..." << "; Size: " << ws.size() << "; Time: " << t2 - t1 << "ms" << endl; return 0;}
Delphi:
program StrPerformanceTest;{$APPTYPE CONSOLE}{$R *.res}uses System.SysUtils, System.DateUtils;const cNumMax = 1000000;function TestViaStringBuilder: string;var SB: TStringBuilder; I : Integer;begin SB := TStringBuilder.Create; for I := 0 to cNumMax - 1 do SB.Append(IntToStr(I)); Result := SB.ToString; FreeAndNil(SB);end;function TestViaNormal: string;var I : Integer;begin Result := ‘‘; for I := 0 to cNumMax - 1 do Result := Result + IntToStr(I);end;var T1: Double; T2: Double; S : string;begin Writeln(‘Starting test with a loop num of ‘, cNumMax, ‘...‘); T1 := Now; S := TestViaStringBuilder; T2 := Now; Writeln(Format(‘Test via TStringBuilder result: %s...(Length = %d); Time: %dms‘, [Copy(S, 2001, 5), Length(S), MilliSecondsBetween(T2, T1)])); T1 := Now; S := TestViaNormal; T2 := Now; Writeln(Format(‘Test via normal-way(+=) result: %s...(Length = %d); Time: %dms‘, [Copy(S, 2001, 5), Length(S), MilliSecondsBetween(T2, T1)])); Readln;end.
Execute 10 times (unit: milliseconds) respectively ). The tragedy is that the string + = operation in golang is too slow. I really don't want to wait, so I only gave the results of using bytes. Buffer officially recommended by golang. In this example, Delphi's use of tstringbuilder does not show any optimizations (fastmm is too powerful !), Therefore, I only gave the common concatenation result (ansistring and string are both native types of Delphi, so there should be no difference in efficiency, so only string is tested here ).
Golang: 141 148 134 119 133 123 145 127 122 132, average: 132.4;
C ++ (STD: string): 384 400 384 385 389 391 389 384 390 383 387.9, average;
C ++ (STD: wstring): 519 521 522 521 519 522 518 519 518 518 519.7, average;
Delphi (string): 41 41 41 41 41 41 41 44 41, average: 41.3;
Sure enough, Delphi is ahead. Of course, this is mainly due to fastmm. The open-source Pascal family memory manager is too powerful!
Of course, this test is not fair to C ++, because golang is not written in string mode, but I don't know whether STL or boost has a powerful tool like stringbuilder?
Finally, an example of data-intensive computing is provided. The result is as follows (unit: milliseconds ).
Golang:
package main
import (
"fmt"
"time"
)
const cSize int = 30
type mymatrix [cSize][cSize]int
func mkmatrix(rows, cols int, mx *mymatrix) {
rows--
cols--
count := 1
for r := 0; r <= rows; r++ {
for c := 0; c <= cols; c++ {
mx[r][c] = count
count++
}
}
}
func multmatrix(rows, cols int, m1, m2 *mymatrix, mm *mymatrix) {
rows--
cols--
for i := 0; i <= rows; i++ {
for j := 0; j <= cols; j++ {
val := 0
for k := 0; k <= cols; k++ {
val += m1[i][k] * m2[k][j]
mm[i][j] = val
}
}
}
}
func main() {
var m1, m2, mm mymatrix
mkmatrix(cSize, cSize, &m1)
mkmatrix(cSize, cSize, &m2)
t0 := time.Now()
for i := 0; i <= 100000; i++ {
multmatrix(cSize, cSize, &m1, &m2, &mm)
}
t := time.Since(t0)
fmt.Println(mm[0][0], mm[2][3], mm[3][2], mm[4][4], mm[29][29])
fmt.Println("tick = ", t)
}
C++:
#include "stdafx.h"#include <time.h>#include <iostream>using namespace std;const int MATRIX_SIZE = 30;int Matrix[MATRIX_SIZE][MATRIX_SIZE];void MakeMatrix(int rows, int cols, int mx[MATRIX_SIZE][MATRIX_SIZE]){rows--;cols--;int count = 1;for (int r = 0; r <= rows; r++){for (int c = 0; c <= cols; c++){mx[r][c] = count;count++;}}}void MatrixMult(int rows, int cols, const int m1[MATRIX_SIZE][MATRIX_SIZE], const int m2[MATRIX_SIZE][MATRIX_SIZE], int mx[MATRIX_SIZE][MATRIX_SIZE]){rows--;cols--;int val;for (int i = 0; i <= rows; i++){for (int j = 0; j <= cols; j++){val = 0;for (int k = 0; k <= cols; k++){val += m1[i][k] * m2[k][j];mx[i][j] = val;}}}}int _tmain(int argc, _TCHAR* argv[]){int num = 100000;int m1[MATRIX_SIZE][MATRIX_SIZE], m2[MATRIX_SIZE][MATRIX_SIZE], mx[MATRIX_SIZE][MATRIX_SIZE];MakeMatrix(MATRIX_SIZE, MATRIX_SIZE, m1);MakeMatrix(MATRIX_SIZE, MATRIX_SIZE, m2);clock_t t1 = clock();for (int i = 0; i <= num; i++){MatrixMult(MATRIX_SIZE, MATRIX_SIZE, m1, m2, mx);}clock_t t2 = clock();cout << mx[0][0] << " " << mx[2][3] << " " << mx[3][2] << " " << mx[4][4] << endl;cout << t2 - t1 << " ms" << endl;return 0;}
Delphi:
program Project1;{$APPTYPE CONSOLE}{$R *.res}uses System.SysUtils, System.DateUtils;const cSize = 30;type TMatrix = array[0..cSize - 1, 0..cSize - 1] of Integer;procedure MakeMatrix(Rows, Cols: Integer; var Mx: TMatrix);var R, C, Count: Integer;begin Dec(Rows); Dec(Cols); Count := 1; for R := 0 to Rows do for C := 0 to Cols do begin Mx[R, C] := Count; Inc(Count); end;end;procedure MatrixMult(Rows, Cols: Integer; const M1, M2: TMatrix; var Mx: TMatrix); inline;var I, J, K, Val: Integer;begin Dec(Rows); Dec(Cols); for I := 0 to Rows do for J := 0 to Cols do begin Val := 0; for K := 0 to Cols do Inc(Val, M1[I, K] * M2[K, J]); Mx[I, J] := Val; end;end;var Num, I : Integer; M1, M2, Mx: TMatrix; T1, T2 : Double;begin Num := 100000; MakeMatrix(cSize, cSize, M1); MakeMatrix(cSize, cSize, M2); T1 := Now; for I := 0 to Num do MatrixMult(cSize, cSize, M1, M2, Mx); T2 := Now; WriteLn(Mx[0, 0], ‘ ‘, Mx[2, 3], ‘ ‘, Mx[3, 2], ‘ ‘, Mx[4, 4], ‘ ‘, mx[29, 29]); WriteLn(‘ C = ‘, MilliSecondsBetween(T2, T1), ‘ ms‘);end.
The result is as follows (unit: milliseconds) after 10 executions ).
Golang: 8757 8790 8713 8748 8737 8744 8752 8752 8746 8754, average: 8749.3;
C ++: 1723 1735 1714 1707 1713 1725 1708 1723 1720 1725, average: 1719.3;
Delphi: 2384 2362 2359 2389 2362 2351 2340 2352 2356 2352, average: 2360.7;
In this intensive computation example, golang has poor performance, and golang 'S Compiler optimization has a long way to go. But Delphi is not surprising. It's not so cool and barely acceptable.
So far, it may be possible to preliminarily judge this. golang meets the requirements in most application scenarios in terms of efficiency. If intensive computing is involved, the current better method should be through CGO. Considering golang's powerful goroutine and channel, rich standard libraries (such as network), simplified syntax, and extremely fast Compilation speed (almost comparable to Delphi ), it is feasible to try golang in backend development, and there are indeed many project instances that have already used golang for backend development.
Note: The features of golang in terms of language syntax and parallelism are described later.
Golang efficiency initial (rough) test