======================编辑2016 05 27 16:55解决================= ==
这个问题解决了!感谢@Paul Hankin,你是对的! Java擅长做"对于(){i = i + 1}",所以当我将代码更改为" for(){i = i + i}"时,java输。
(PS:使用Java ExecutorService真的让java结果很好,但仍然不如goroutine,这里没有ExecutorService示例)
Java代码:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String args[]) throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>();
for(int i = 0; i < 10; i ++) {
threads.add(new Thread(new RunableAdd()));
}
long timeStart = System.currentTimeMillis();
for(Thread t: threads) {
t.start();
}
for(Thread t: threads) {
t.join();
}
System.out.println("Time Use : " + (System.currentTimeMillis() - timeStart) + "ms");
}
}
class RunableAdd implements Runnable {
@Override
public void run() {
long i = 1;
while(true) {
i += i;
if (i > 1000 * 1000* 1000) {
return;
}
}
}
}
Golang代码:
package main
import (
"fmt"
"time"
)
func main() {
chanSignal := make(chan bool)
startTime := time.Now()
goroutineNum := 10
for i := 0; i < goroutineNum; i++ {
go func() {
j := 1
for {
j = j + j
if j > 1000*1000*1000 {
chanSignal <- true
return
}
}
}()
}
for i := 0; i < goroutineNum; i++ {
<-chanSignal
}
fmt.Println(time.Since(startTime))
}
结果:
Thread / goroutine num:10
java : Time Use : 4ms
golang : 19.105µs
Thread / goroutine num:100
java : Time Use : 27ms
golang : 180.272µs
Thread / goroutine num:1000
java: Time Use : 512ms
golang : 1.565521ms
事实证明golang很好,java很擅长&#34; i = i + 1&#34;,
在goroutine num pluse 10中,时间成本低于10倍。
===============================结束=============== =====================
我今天用java线程测试golang goroutine,我认为golang goroutine应该比java Thread快,但我的测试结果显示java线程获胜。
环境: java 1.8 golang 1.6
cpu是4核心
$ cat /proc/cpuinfo | grep 'core id'
core id : 0
core id : 0
core id : 1
core id : 1
Java代码:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String args[]) throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>();
for(int i = 0; i < 100; i ++) {
threads.add(new Thread(new RunableAdd()));
}
long timeStart = System.currentTimeMillis();
for(Thread t: threads) {
t.start();
}
for(Thread t: threads) {
t.join();
}
System.out.println("Time Use : " + (System.currentTimeMillis() - timeStart) + "ms");
}
}
class RunableAdd implements Runnable {
@Override
public void run() {
int i = 0;
while(true) {
i ++;
if (i == 10 * 1000* 1000) {
return;
}
}
}
}
golang代码:
package main
import (
"fmt"
"time"
)
func main() {
chanSignal := make(chan bool)
startTime := time.Now()
goroutineNum := 100
for i := 0; i < goroutineNum; i++ {
go func() {
j := 0
for {
if j == 10*1000*1000 {
chanSignal <- true
return
} else {
j = j + 1
}
}
}()
}
for i := 0; i < goroutineNum; i++ {
<-chanSignal
}
fmt.Println(time.Since(startTime))
}
结果是:
当我设置线程数10:
Java : Time Use : 18ms
golang : 50.952259ms
线程数100:
Java : Time Use : 88ms
golang : Time Use : 458.239685ms
线程数1000:
Java : Time Use : 1452ms
golang : 4.701811465s
Java Thread真的比golang goroutine快吗?或者我的程序做错了什么?
答案 0 :(得分:3)
基准很难做到正确,当你测量其他东西时,很容易认为你正在测量一件事(goroutines /线程的成本)。我认为这是在这里发生的事情。
例如,thread / goroutines中的内部循环在两个程序中是相同的。将goroutine重写为更像java代码:
for j := 0; j != 10*1000*1000; j++ {}
chanSignal <- true
带来了2倍的加速。
当我在我的机器上运行它时仍然会留下显着的性能差距 - go代码需要663ms,1000 goroutines,java代码55ms,1000个线程。也许正在发生的事情是,JVM在执行了几次后,在线程的run
方法中JITting掉了无用的循环。
这里有一些证据表明goroutines的成本并不相关。只是串行执行代码,我的机器上的运行时间为2.55秒:
package main
import (
"fmt"
"time"
)
func main() {
goroutineNum := 1000
startTime := time.Now()
for i := 0; i < goroutineNum; i++ {
for j := 0; j < 1000*1000*10; j++ {
}
}
fmt.Println(time.Since(startTime))
}
这个代码的基于goroutine的版本在4个处理器上运行,长度为663毫秒,仅略高于串行代码所用2.55秒的四分之一(在我的机器上)。所以这是非常有效的并行性,并且goroutine的成本可以忽略不计。
因此大多数情况下,我认为您正在对java的执行效率进行基准测试并执行空循环。对于JIT来说,这似乎是一个完美的用例,您可以在Java代码的出色运行时性能中看到它。
答案 1 :(得分:0)
i = i + i测试是愚蠢的,因为它几乎只执行了24次添加和24次测试。比较,我相信我们都承认我们经常遇到现实世界的问题,只需要48个机器指令即可完成。
而不是Thread,Executors.newFixedThreadPool更接近Java相当于goroutine,尝试热身,你可能得到不同的结果。