java - Golang 与 Java 的速度

标签 java go

我用 Java 写了一个程序,用 Go 写了一个等价的程序。我的 java 程序执行大约需要 5.95 秒,而 Go 程序大约需要 41.675789791 秒。虽然 Go 的速度与 C 或 C++ 相当,因为它像 C 一样编译,但为什么存在如此大的性能差异?程序如下:

Go 程序

package main


import (
    "math"
    "fmt"
    "time"
)

func main() {
    fmt.Printf("vvalue is %v", testFun(10, 16666611, 1000000000))
}

func fun(x float64) float64 {
    return math.Pow(x, 2) - x
}

func testFun(first float64, second float64, times int) float64 {
    var i = 0
    var result float64 = 0
    var dx float64
    dx = (second - first) / float64(times)
    for ; i < times; i++ {
        result += fun(first + float64(i) * dx)
    }
    return result * dx
}   

Java 程序

public class Test {
public static void main(String[] args) {
    Test test = new Test();
    double re = test.testFun(10, 16666611, 1000000000);
    System.out.println(re);
}

private double testFun(double first, double second, long times) {
    int i = 0;
    double result = 0;
    double dx = (second - first) / times;
    for (; i < times; i++) {
        result += fun(first + i * dx);
    }
    return result * dx;
}

private double fun(double v) {
    return Math.pow(v, 2) - v;
}
}

最佳答案

(根据上述答案的提示,我做了更多测试,并添加了一个 C 版本)

在我的 Linux 机器上,times = 100000000

测试结果:

  • 当指数 = 2.4
 Java: result: 1.053906e+24, during: 7432 ms
    C: result: 1.053906e+24, during: 5544 ms
   Go: result: 1.053906e+24, during: 8.716807708s
  • 当指数=2时,仍然使用pow()Pow()
 Java: result: 1.543194e+21, during: 630 ms
    C: result: 1.543194e+21, during: 852 ms
   Go: result: 1.543194e+21, during: 3.336549272s
  • 当指数 = 2 时,但使用 x * x 代替。
 Java: result: 1.543194e+21, during: 636 ms
    C: result: 1.543194e+21, during: 340 ms
   Go: result: 1.543194e+21, during: 115.491272ms

总结:

  • 总的来说,go真的很快,根据上次的测试,比Java,甚至C都快。
  • 但是,根据前 2 个测试,Java 确实有一个很好的 pow() 实现。

代码

测试.java:

/**
 * Compile:
 *  javac Test.java
 * Run:
 *  java Test
 */ 
public class Test {
    public static void main(String[] args) {
        Test test = new Test();
    long startAt = System.currentTimeMillis();
        double re = test.testFun(10, 16666611, 100000000);
    long during = System.currentTimeMillis() - startAt;
        System.out.printf("%10s: result: %e, during: %d ms\n", "Java", re, during);
    }

    private double testFun(double first, double second, long times) {
        int i = 0;
        double result = 0;
        double dx = (second - first) / times;
        for (; i < times; i++) {
            result += fun(first + i * dx);
        }
        return result * dx;
    }

    private double fun(double v) {
        return v * v - v;
        // return Math.pow(v, 2) - v;
        // return Math.pow(v, 2.4) - v;
    }
}

测试.c:

/**
 * compile with:
 *  gcc test.c -lm
 */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

double fun(double v) {
    return v * v - v;
    // return pow(v, 2) - v;
    // return pow(v, 2.4) - v;
}

double testFun(double first, double second, long times) {
    int i;
    double result = 0;
    double dx = (second - first) / times;
    for (i = 0; i < times; i++) {
        result += fun(first + i * dx);
    }
    return result * dx;
}

long long current_timestamp() {
    struct timeval te;
    gettimeofday(&te, NULL); // get current time
    long long milliseconds =
        te.tv_sec * 1000LL + te.tv_usec / 1000; // calculate milliseconds
    // printf("milliseconds: %lld\n", milliseconds);
    return milliseconds;
}

int main(int argc, char *argv[]) {
    long long startAt = current_timestamp();
    double re = testFun(10, 16666611, 100000000);
    long long during = current_timestamp() - startAt;
    printf("%10s: result: %e, during: %lld ms\n", "C", re, during);
    return 0;
}

测试.go:

/**
 * How to run:
 *  go run test.go
 */
package main

import (
    "fmt"
    "math"
    "time"
)

func main() {
    startAt := time.Now()
    result := testFun(10, 16666611, 100000000)
    during := time.Since(startAt)
    fmt.Printf("%10s: result: %e, during: %v\n", "Go", result, during)

    _ = math.Pow
}

func fun(x float64) float64 {
    return x*x - x
    // return math.Pow(x, 2) - x
    // return math.Pow(x, 2.4) - x
}

func testFun(first float64, second float64, times int) float64 {
    var i = 0
    var result float64 = 0
    var dx float64
    dx = (second - first) / float64(times)
    for ; i < times; i++ {
        result += fun(first + float64(i)*dx)
    }
    return result * dx
}

编译:

javac Test.java; gcc test.c -lm; go build test.go

运行:

java Test; ./a.out ; ./test

@Update - 带有-O2-O3 选项的C 程序

Raffaello在评论中建议,在编译C程序时,可以使用-O2-O3来进一步优化程序。

C程序的测试结果如下:

  • 当指数 = 2.4
            C: result: 1.543194e+21, during: 5805 ms
 C with `-O2`: result: 1.543194e+21, during: 5324 ms
 C with `-O3`: result: 1.543194e+21, during: 5326 ms
  • 当指数=2时,仍然使用pow()Pow()
            C: result: 1.543194e+21, during: 897 ms
 C with `-O2`: result: 1.543194e+21, during: 119 ms
 C with `-O3`: result: 1.543194e+21, during: 121 ms
  • 当指数 = 2 时,但使用 x * x 代替。
            C: result: 1.543194e+21, during: 353 ms
 C with `-O2`: result: 1.543194e+21, during: 122 ms
 C with `-O3`: result: 1.543194e+21, during: 119 ms

总结 -(-O2-O3 选项):

  • 带有 -O2-O3 选项
    • 当基数是整数(例如 2) 时,将使 c 程序更快,快几倍。
    • 当基数是 float 时(例如 2.4),它也更快,但非常小。
  • 比较-O2-O3,它们在上述测试中非常接近。

关于java - Golang 与 Java 的速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51806224/

相关文章:

java - 如何重构这种类型的 switch-case 语句?

java - 禁用 JShell 历史记录

java - 使用 ParameterNameAware 接口(interface)避免参数篡改 (Struts2)

go - 从Go lang的dynamodb表中获取所有唯一值

http - 计算在 Go 中调用(请求处理程序)函数的次数

go - 提示多用户输入失败

java - 将按钮添加到 TableView 中的单元格 (JAVAFX)

go - 两个节点可以直接交换消息吗?

session - 在 Golang 中跟踪在线用户

java - 在 Java 中实现 JOptionPane