为了账号安全,请及时绑定邮箱和手机立即绑定

为什么用 Golang 写的一些函数运行起来比用 Java 还要慢?

为什么用 Golang 写的一些函数运行起来比用 Java 还要慢?

Go
慕姐4208626 2023-06-01 18:10:05
我用 Golang 和 Java 测试了几个简单的函数。令我惊讶的是,Java 有时比 Golang 更快(尤其是在递归函数和标准库中的某些函数,如 math/rand.Rand)。我想知道为什么。这是我用于测试的一些代码和结果。Java代码:public class Performance {    public static double calPi(int pointCount) {        int inCircleCount = 0;        double x, y;        double Pi;        for (int i = 0; i < pointCount; i++) {            x = Math.random();            y = Math.random();            if (x * x + y * y < 1) {                inCircleCount++;            }        }        Pi = (4.0 * inCircleCount) / pointCount;        return Pi;    }    public static double cal(double a, double b, double c) {        return a * b / (c + 1) + a;    }    public static long fibonacci(long c) {        if (c < 2)            return c;        return fibonacci(c - 2) + fibonacci(c - 1);    }    public static void main(String[] args) {        System.out.println("Test 1");        long startTime = System.currentTimeMillis();        double result = 0.0;        for (double i = 0.0; i < 1000000000; i = i + 1) {            result += i * i;        }        long endTime = System.currentTimeMillis();        float duration = (float) (endTime - startTime) / 1000;        System.out.println("Result: " + result);        System.out.println("Duration: " + duration + " s");        System.out.println("Test 2");        startTime = System.currentTimeMillis();        long resultInt = fibonacci(50);        endTime = System.currentTimeMillis();        duration = (float) (endTime - startTime) / 1000;        System.out.println("Result: " + resultInt);        System.out.println("Duration: " + duration + " s");        System.out.println("Test 3");        startTime = System.currentTimeMillis();        result = 0.0;        for (double i = 0; i < 100000000; i = i + 1) {            result += Math.random();        }        endTime = System.currentTimeMillis();        duration = (float) (endTime - startTime) / 1000;    }}Test 2结果的差异真的让我震惊!请帮我找出原因,谢谢。如果有人可以给我示例来展示 Golang(与 Java)的优势,那就更好了。
查看完整描述

1 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

Java 和 Golang 程序在执行之前都被编译成机器语言——这就是 JIT 代表 Java VM 的意思。至于性能比较,每个生成的机器码之间肯定有不那么细微的差异。


不幸的是,我无法访问 Java JIT 编译器生成的机器码,但我们可以看一下 Go 编译器(v1.11.4-amd64)为函数生成的内容fibonacci:


        # Do the comparison

        MOVQ    "c", AX

        CMPQ    AX, $2

        JGE     @ELSE

        # Save the func result

        MOVQ    AX, "r"

        # Clean up and return

        MOVQ    24(SP), BP

        ADDQ    $32, SP

        RET

@ELSE:

        # Compute fib(c - 2)

        LEAQ    -2(AX), CX

        MOVQ    CX, (SP)

        CALL    fibonacci

        # Save the call result

        MOVQ    8(SP), AX

        MOVQ    AX, "temp"

        # Compute fib(c - 1)

        MOVQ    "c", CX

        DECQ    CX

        MOVQ    CX, (SP)

        CALL    fibonacci

        # Add previous results together

        MOVQ    16(SP), AX

        ADDQ    8(SP), AX

        # Save the func result

        MOVQ    AX, "r"

        # Clean up and return

        MOVQ    24(SP), BP

        ADDQ    $32, SP

        RET

请注意,这段代码不是完全相同的输出,但我对其进行了一些修改以使其更加清晰。引用的变量是堆栈位置。


我的结论是,虽然 Go 编译器确实采用了一些优化技术来生成更高性能的代码(请参阅编译器优化),但它在分配 CPU 寄存器方面做得不是很好(与 C 编译器生成的相比),并且依赖于堆栈太多,尤其是对于返回值——我认为必须有一个可能与语言工作方式相关的原因(例如多个返回值)。


更新 1


只是为了比较,这是 GCC (amd64) 为相同功能生成的机器码:


        pushq %rbp

        movq  %rsp, %rbp

        pushq %r14

        pushq %rbx

        # Do the comparison

        movq  %rdi, %rbx

        cmpq  $2, %rbx

        jge @ELSE

        # Save "c" in "r"

        movq  %rbx, %rax

        jmp @RETURN

@ELSE:

        # Compute fib(i - 2)

        leaq  -2(%rbx), %rdi

        callq fibonacci

        # Compute fib(i - 1)

        movq  %rax, %r14

        decq  %rbx

        movq  %rbx, %rdi

        callq fibonacci

        # Add previous results together

        addq  %r14, %rax

@RETURN:

        popq  %rbx

        popq  %r14

        popq  %rbp

        retq

更新 2


话虽如此,我坚信在实际项目中,语言运行时(例如对象分配、垃圾收集、调用间接、动态加载、并发支持等)会对程序的整体性能产生更大的影响,而不是功能级别的微优化。


查看完整回答
反对 回复 2023-06-01
  • 1 回答
  • 0 关注
  • 134 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信