Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Go中的这个简单循环比C中的快?_C_Go_Benchmarking_Compiler Optimization_Computer Architecture - Fatal编程技术网

为什么Go中的这个简单循环比C中的快?

为什么Go中的这个简单循环比C中的快?,c,go,benchmarking,compiler-optimization,computer-architecture,C,Go,Benchmarking,Compiler Optimization,Computer Architecture,我试图找出Go的循环性能是否和C的一样好,但令人惊讶的是,对于我的简单测试,C版本花费的时间是Go版本的两倍 C版本: #include <stdio.h> int main() { int i = 0, a = 0; while (i < 1e9) { a = (a + i) % 42; i = i + 1; } printf("%d\n", a); } Go版本: package main import "fmt" func mai

我试图找出Go的循环性能是否和C的一样好,但令人惊讶的是,对于我的简单测试,C版本花费的时间是Go版本的两倍

C版本:

#include <stdio.h>

int main() {
  int i = 0, a = 0;

  while (i < 1e9) {
    a = (a + i) % 42;
    i = i + 1;
  }
  printf("%d\n", a);
}
Go版本:

package main

import "fmt"

func main() {
    a := int32(0)
    for i := int32(0); i < 1e9; i++ {
        a = (a + i) % 42
    }
    fmt.Println(a)
}
在达尔文进行测试,amd64

对于这个简单的算法,它们不应该产生几乎相同的机器代码吗?这是因为编译器优化吗?缓存效率


请帮我理解!谢谢

它们在优化时的时间大致相同。比如说,

去:

C:


它们在优化时的时间差不多相同。比如说,

去:

C:


这一切归结为生成的程序集

go工具6g-S 21说明:

MOVL    $0,SI
MOVL    SI,"".a+8(FP)
MOVL    $0,CX
CMPL    CX,$1000000000
JGE     $0,58
ADDL    CX,SI
MOVL    $818089009,BP
MOVL    SI,AX
IMULL   BP,
MOVL    DX,BX
SARL    $3,BX
MOVL    SI,BP
SARL    $31,BP
SUBL    BP,BX
IMULL   $42,BX
SUBL    BX,SI
MOVL    SI,"".a+8(FP)
INCL    ,CX #point A
NOP     ,
CMPL    CX,$1000000000
JLT     $0,16
RET     ,
leal    (%rsi,%rcx), %edi
addl    $1, %ecx
vxorpd  %xmm0, %xmm0, %xmm0
vcvtsi2sd       %ecx, %xmm0, %xmm0
movl    %edi, %eax
imull   %r8d
movl    %edi, %eax
sarl    $31, %eax
sarl    $3, %edx
movl    %edx, %esi
subl    %eax, %esi
imull   $42, %esi, %esi
subl    %esi, %edi
vucomisd        %xmm0, %xmm1
movl    %edi, %esi
ja      .L2
subq    $8, %rsp
gcc-O3-march=本机-S 17说明:

MOVL    $0,SI
MOVL    SI,"".a+8(FP)
MOVL    $0,CX
CMPL    CX,$1000000000
JGE     $0,58
ADDL    CX,SI
MOVL    $818089009,BP
MOVL    SI,AX
IMULL   BP,
MOVL    DX,BX
SARL    $3,BX
MOVL    SI,BP
SARL    $31,BP
SUBL    BP,BX
IMULL   $42,BX
SUBL    BX,SI
MOVL    SI,"".a+8(FP)
INCL    ,CX #point A
NOP     ,
CMPL    CX,$1000000000
JLT     $0,16
RET     ,
leal    (%rsi,%rcx), %edi
addl    $1, %ecx
vxorpd  %xmm0, %xmm0, %xmm0
vcvtsi2sd       %ecx, %xmm0, %xmm0
movl    %edi, %eax
imull   %r8d
movl    %edi, %eax
sarl    $31, %eax
sarl    $3, %edx
movl    %edx, %esi
subl    %eax, %esi
imull   $42, %esi, %esi
subl    %esi, %edi
vucomisd        %xmm0, %xmm1
movl    %edi, %esi
ja      .L2
subq    $8, %rsp
gcc-O3-march=native-s14指令,在将1e9替换为100000000之后:

leal    (%rdx,%rcx), %esi
addl    $1, %ecx
movl    %esi, %eax
imull   %edi
movl    %esi, %eax
sarl    $31, %eax
sarl    $3, %edx
subl    %eax, %edx
imull   $42, %edx, %edx
subl    %edx, %esi
movl    %esi, %edx
cmpl    $1000000000, %ecx
jne     .L2
subq    $8, %rsp
时间:

$ gcc -O3 -march=native loop.c; and time ./a.out
36
2.92user 0.00system 0:02.93elapsed 99%CPU
$ go build -o loop loop.go; and time ./loop
36
2.89user 0.00system 0:02.90elapsed 99%CPU
$ gcc -O3 -march=native loop_nofp.c; and time ./a.out
36
2.92user 0.00system 0:02.94elapsed 99%CPU (0avgtext+0avgdata 1312maxresident)
我不知道,我现在就把这个留到合适的答案发布之前

//编辑

将C代码更改为用于匹配Go版本会产生不同的程序集,但时间完全相同

int main() {
    int32_t i = 0, a = 0;
    for (i = 0; i < 1e9; i++) {
        a = (a + i) % 42;
    }
    printf("%d\n", a);
    return 0;
}

这一切归结为生成的程序集

go工具6g-S 21说明:

MOVL    $0,SI
MOVL    SI,"".a+8(FP)
MOVL    $0,CX
CMPL    CX,$1000000000
JGE     $0,58
ADDL    CX,SI
MOVL    $818089009,BP
MOVL    SI,AX
IMULL   BP,
MOVL    DX,BX
SARL    $3,BX
MOVL    SI,BP
SARL    $31,BP
SUBL    BP,BX
IMULL   $42,BX
SUBL    BX,SI
MOVL    SI,"".a+8(FP)
INCL    ,CX #point A
NOP     ,
CMPL    CX,$1000000000
JLT     $0,16
RET     ,
leal    (%rsi,%rcx), %edi
addl    $1, %ecx
vxorpd  %xmm0, %xmm0, %xmm0
vcvtsi2sd       %ecx, %xmm0, %xmm0
movl    %edi, %eax
imull   %r8d
movl    %edi, %eax
sarl    $31, %eax
sarl    $3, %edx
movl    %edx, %esi
subl    %eax, %esi
imull   $42, %esi, %esi
subl    %esi, %edi
vucomisd        %xmm0, %xmm1
movl    %edi, %esi
ja      .L2
subq    $8, %rsp
gcc-O3-march=本机-S 17说明:

MOVL    $0,SI
MOVL    SI,"".a+8(FP)
MOVL    $0,CX
CMPL    CX,$1000000000
JGE     $0,58
ADDL    CX,SI
MOVL    $818089009,BP
MOVL    SI,AX
IMULL   BP,
MOVL    DX,BX
SARL    $3,BX
MOVL    SI,BP
SARL    $31,BP
SUBL    BP,BX
IMULL   $42,BX
SUBL    BX,SI
MOVL    SI,"".a+8(FP)
INCL    ,CX #point A
NOP     ,
CMPL    CX,$1000000000
JLT     $0,16
RET     ,
leal    (%rsi,%rcx), %edi
addl    $1, %ecx
vxorpd  %xmm0, %xmm0, %xmm0
vcvtsi2sd       %ecx, %xmm0, %xmm0
movl    %edi, %eax
imull   %r8d
movl    %edi, %eax
sarl    $31, %eax
sarl    $3, %edx
movl    %edx, %esi
subl    %eax, %esi
imull   $42, %esi, %esi
subl    %esi, %edi
vucomisd        %xmm0, %xmm1
movl    %edi, %esi
ja      .L2
subq    $8, %rsp
gcc-O3-march=native-s14指令,在将1e9替换为100000000之后:

leal    (%rdx,%rcx), %esi
addl    $1, %ecx
movl    %esi, %eax
imull   %edi
movl    %esi, %eax
sarl    $31, %eax
sarl    $3, %edx
subl    %eax, %edx
imull   $42, %edx, %edx
subl    %edx, %esi
movl    %esi, %edx
cmpl    $1000000000, %ecx
jne     .L2
subq    $8, %rsp
时间:

$ gcc -O3 -march=native loop.c; and time ./a.out
36
2.92user 0.00system 0:02.93elapsed 99%CPU
$ go build -o loop loop.go; and time ./loop
36
2.89user 0.00system 0:02.90elapsed 99%CPU
$ gcc -O3 -march=native loop_nofp.c; and time ./a.out
36
2.92user 0.00system 0:02.94elapsed 99%CPU (0avgtext+0avgdata 1312maxresident)
我不知道,我现在就把这个留到合适的答案发布之前

//编辑

将C代码更改为用于匹配Go版本会产生不同的程序集,但时间完全相同

int main() {
    int32_t i = 0, a = 0;
    for (i = 0; i < 1e9; i++) {
        a = (a + i) % 42;
    }
    printf("%d\n", a);
    return 0;
}

您的C程序是在没有任何优化的情况下编译的。Go编译器可能有不同的默认值,并且在没有指示的情况下进行优化。使用gcc-O2进行编译以进行更公平的比较。@delnan for go:go编译器生成的代码默认情况下是“优化”的:源代码:通过使用asm,两者都可以比较go,这类似于go build-gcflags-s。我很难理解,但你的go使用的是32位整数,而C可能使用的是64位整数,也许64位除法是一种慢得多的指令。或者Go在这里有一些优化,但在gcc的默认优化级别上没有。关于@delnan,。为什么要比较不同的代码???至少你应该对两者使用相同的代码或while。你的C程序是在没有任何优化的情况下编译的。Go编译器可能有不同的默认值,并且在没有指示的情况下进行优化。使用gcc-O2进行编译以进行更公平的比较。@delnan for go:go编译器生成的代码默认情况下是“优化”的:源代码:通过使用asm,两者都可以比较go,这类似于go build-gcflags-s。我很难理解,但你的go使用的是32位整数,而C可能使用的是64位整数,也许64位除法是一种慢得多的指令。或者Go在这里有一些优化,但在gcc的默认优化级别上没有。关于@delnan,。为什么要比较不同的代码???至少您应该为两者使用相同的函数或while。即使在i7上使用gcc-O3-march=native,Go仍然只快一点点。+-Go即使在i7上使用gcc-O3-march=native,仍然只快一点点。+-MOVL$…,BP指令是Go用一系列乘法和移位替换除法模运算符的一部分。GCC在优化C中做了类似的事情。MOVL$…,BP指令是go用乘法和移位序列替换除法模运算符的一部分。GCC在优化的C中做了类似的事情。