Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speed of Golang Vs Java

Tags:

java

go

I have written a program in Java and equivalent in Go. My java program is taking around 5.95 seconds to execute while Go program is taking around 41.675789791 seconds. While speed of Go is comparable to C or C++ as it is compiled like C then Why this much of performance difference exists? Programs are as follows:

Go Program

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 Program

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;
}
}
like image 355
ankur agrawal Avatar asked Nov 27 '22 20:11

ankur agrawal


2 Answers

(With tips from above answers, I did more test, with an additional C version)

On my linux machine, with times = 100000000.

Testing result:

  • When exponent = 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
  • When exponent = 2, still use pow() or 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
  • When exponent = 2, but use x * x instead.
 Java: result: 1.543194e+21, during: 636 ms
    C: result: 1.543194e+21, during: 340 ms
   Go: result: 1.543194e+21, during: 115.491272ms

Summary:

  • In general, go is really fast, according to the last test, faster than Java, or even C.
  • But, Java really have a good pow() implementation, according to the first 2 test.

Code

Test.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;
    }
}

test.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;
}

test.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
}

Compile:

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

Run:

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

@Update - C program with -O2 or -O3 option

As suggested by Raffaello in the comment, when compiling C program, could use -O2 or -O3 to further optimize the program.

And, following are the test result for C program:

  • When exponent = 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
  • When exponent = 2, still use pow() or 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
  • When exponent = 2, but use x * x instead.
            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

Summary - (-O2 and -O3 option):

  • With -O2 and -O3 option
    • When base is integer (e.g 2), would make c program quicker, by several times.
    • When base is floating point number (e.g 2.4), it's also quicker, but very minimal.
  • Comparing between -O2 and -O3, they are quite close in above tests.
like image 179
user218867 Avatar answered Dec 05 '22 10:12

user218867


Don't translate from another language. Write the Go version of your program in Go. For example, x*x - x,

package main

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

func main() {
    start := time.Now()
    v := testFun(10, 16666611, 1000000000)
    since := time.Since(start)
    fmt.Printf("value is %v\ntime is %v\n", v, since)
}

func fun(x float64) float64 {
    return x*x - x
}

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

Output:

$ go version
go version devel +5c11480631 Fri Aug 10 20:02:31 2018 +0000 linux/amd64
$ go run speed.go
value is 1.543194272428967e+21
time is 1.011965238s
$

What results do you get?

like image 22
peterSO Avatar answered Dec 05 '22 11:12

peterSO