golang += 性能很差?

Elvis.Xiong 发布于 2013/11/25 22:52
阅读 19K+
收藏 7
Go

做一个简单的1加到9000000000计算题

1、使用count +=1 进行运算

calc1.go


import "fmt"
import "time"

func main(){
    
    t1 := time.Now()
    count :=0 
    for i :=0; i< 9000000000; i++{
        count += i

    }   
    t2 := time.Now()
    fmt.Printf("cost:%d,count:%d\n",t2.Sub(t1),count)

}

# go build calc1.go

#./calc1

# cost:16288809060,count:3606511848080896768

运行总时间 16s

使用count = count +1

package main

import "fmt"
import "time"

func main(){
    
    t1 := time.Now()
    count :=0 
    for i :=0; i< 9000000000; i++{
        count =count +i

    }   
    t2 := time.Now()
    fmt.Printf("cost:%d,count:%d\n",t2.Sub(t1),count)

}



#go build calc2.go

#./calc2

#cost:5530773389,count:3606511848080896768


总运行时间 5.5s

3、再来看看java的表现

public class calc3{

    public static long sum(long a){
        long sum = 0;

        for(long i =0 ;i <a;i++){

            sum += i;
        }

        return sum;

    }


    public static void main(String[] args){

        System.out.println("1 to 9000000000 sum:"+sum(9000000000l)+"");

    }


}



总运行时间5.9s 

4、golang的杀手功能goroutine PK一把

package main

import "fmt"
import "runtime"
import "time"

func  run(i,n int ,ch chan int){
    count := 0
    for i := i; i < n; i++ {
        count = count +i
    }   
    ch <- count

}

func main(){
    
    t1 := time.Now()
    NCPU := runtime.NumCPU()
    runtime.GOMAXPROCS(NCPU)
    chs := make([] chan int,NCPU)
    for i :=0; i < NCPU; i++{
        chs[i] = make(chan int)
        n := 9000000000/NCPU
        go run(i*n, (i+1)*n,chs[i])
    }   
    
    count := 0
    for i :=0; i < NCPU;i++{
        t := <- chs[i]
        count = count +t
    }   
    t2 := time.Now()

    fmt.Printf("cpu num:%d,cost:%d,count:%d\n",NCPU,t2.Sub(t1),count)
}



# go build calc4.go

#./calc4

#cpu num:4,cost:2965606645,count:3606511848080896768

总运行时间仅2.9s,WOW!,可见goroutine还是名不虚传的

总结:1、golang的+=编译生成的代码有性能问题,建议替换为count = count +i这种表达式

        2、golang在单线程下比java稍快一点

        3、golang并行计算优势明显





加载中
0
巫云
巫云
+= 竟然会比较慢?估计是编译的问题,说不定下个版本就修复了等12.1发新版吧。 goroutine 是多线程自然快一点。
0
Elvis.Xiong
Elvis.Xiong

引用来自“巫云”的答案

+= 竟然会比较慢?估计是编译的问题,说不定下个版本就修复了等12.1发新版吧。 goroutine 是多线程自然快一点。
估记是编译器的bug,性能差的也太大了
0
红薯
红薯
呀,开始玩 go 了?
0
独孤小败
独孤小败

package main

import "fmt"
import "time"

func main() {

	t1 := time.Now()
    var count int64
    var i int64
	count = 0
	for i = 0; i < 9000000000; i++ {
		// count += i     // cost:10609606800,count:3606511848080896768
        count = count + i // cost:10618607400,count:3606511848080896768

	}
	t2 := time.Now()
	fmt.Printf("cost:%d,count:%d\n", t2.Sub(t1), count)

}



因为我这是32位的系统,开始提示,900...超出int的长度了,然后我把他们都写成了int64后,发现跟楼主不一样的结论了。



0
忆童
忆童
上面的计算方法是不合理的,因为对于未声明的int,golang默认是转为 int64 类型的,你如果指定i 为int 32 就会快很多了,go 的for 循环速率比java快至少20%以上
Elvis.Xiong
Elvis.Xiong
可能windows下编译器实现不同,楼主使用的是linux64位系统
忆童
忆童
回复 @独孤小败 : 用int32可支持的数字测试下,和java差不多的
独孤小败
独孤小败
constant 9000000000 overflows int32
0
王振威
王振威

64位mac,得出了跟楼主一样的结论

0
忆童
忆童
xp下,go的int64和java的lang,10亿次循环,go比java快
0
相见欢
相见欢

楼主,你好~本着科学严谨的态度,对你最后那个goroutine的代码进行了一点小修改,保证数组的边界不会超出9000000000。

package main

import "fmt"
import "runtime"
import "time"

func run(i, n int, ch chan int) {
	count := 0
	for i := i; i < n; i++ {
		count = count + i
	}
	ch <- count

}

func main() {

	t1 := time.Now()
	//NCPU := runtime.NumCPU()
	NCPU := 1000
	runtime.GOMAXPROCS(NCPU)
	chs := make([]chan int, NCPU)
	n := 9000000000 / NCPU
	var start, end int
	for i := 0; i < NCPU; i++ {
		chs[i] = make(chan int)
		start = i*n
		if i==NCPU-1{
			end=9000000000
		}else{
			end = (i+1)*n
		}
		//fmt.Printf("i=%d, range:[%d, %d)\n", i, start, end)
		go run(start, end, chs[i])
	}

	count := 0
	for i := 0; i < NCPU; i++ {
		t := <-chs[i]
		count = count + t
	}
	t2 := time.Now()

	fmt.Printf("cpu num:%d,cost:%fs,count:%d\n", NCPU, t2.Sub(t1).Seconds(), count)
}



经过实验,发现将NCPU的值增加可以进一步减小时延,但是增加到一定的数值,反而会增大时延。我在服务器上试了一下,runtime.NumCPU()返回的是24,你可以在代码里面看到,我将NCPU手工增加,1000和10000两个数量级,会达到时延的拐点,10000的时候,花费时间比1000要更大。

生命不息,折腾不止!

Elvis.Xiong
Elvis.Xiong
这样CPU资源都被榨干了,少量增加可能提升性能,是因为榨干了个每个协程的空闲时间。我感觉没必要超的太多,CPU还是要留下一点资源给OS管理的其它进程。
0
王振威
王振威

10000个goroutin cpu都忙着切换线程了

ifsc01
ifsc01
回复 @Elvis.Xiong : 你既然开了协程,为什么不加上GOMAXPROCS
Elvis.Xiong
Elvis.Xiong
回复 @王振威 : goroutine是线程内部的任务,所以不会来回切换,从根本上说应该认为groutine就是go语言版的协程, groutine的实现者是libtask的作者。
王振威
王振威
回复 @Elvis.Xiong : 据说go的并发就是线程池
相见欢
相见欢
回复 @Elvis.Xiong : 协程好像是elang里面的概念,官方对goroutine的定义明确说,它不是协程,记得里面说的就是一个函数,应该会有不少好文章会说到这个主题,我回头找找。
Elvis.Xiong
Elvis.Xiong
准确来说是协程
0
开源狂人
开源狂人

为什么这么比?go和java比这个东西呢???

你开着阿斯顿马丁和一个悍马比速度???不觉得无聊吗?

为什么不和C比一比呢?

返回顶部
顶部