Golang efficiency initial (rough) test

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.