laputa73 发表于 2013-11-13 13:22

[练习]go版的击鼓传花

这个是erlang的一个练习.从前有人用来展现stackelss python的性能如何牛.
学习go的goroutine,也照猫画虎来一个.
go的协程有些特别.没有join等待协程结束,所以用了一个结果队列(类似perl)
channel的写入默认也是非缓冲(阻塞方式)的
总体来看,go的协程性能相当之好,即使是go run方式,类似脚本运行,也比python,perl快不少

编程的风格和c很象
数组作为函数参数,这块没有具体研究是传值还是传指针
想当然地按c的方式处理了/*
go版的击鼓传花(erlang和stackless的经典例子)
由n个节点组成一个环状网络,在上面传送共m个消息。
将每个消息(共m个),逐个发送给1号节点。
第1到n-1号节点在接收到消息后,都转发给下一号节点。
第n号节点每次收到消息后,不再继续转发。
当m个消息都从1号逐个到达第n号节点时,认为全部处理结束。
每次执行时设定n=300,m=10000
*/
package main
import (
"flag"
"fmt"
//"os"
"strconv"
)

var n,m int

//3.定义节点(协程)
func node(i int,ch []chan int,result chan int){
        for{
                msg:= <-ch
                //fmt.Println("node ", i," got msg ",msg)
                if i>=n-1 {
                        //fmt.Println("msg ", msg," reached last node ",i)
                        if msg>=m-1 {
                                fmt.Println("final msg send back")
                                result <- msg
                        }
                }else{
                        //fmt.Println("node ", i," pass msg",msg," to next node")
                        ch <- msg
                }
        }
}

func main() {
        //1.输入参数处理
        flag.Parse()
        args := flag.Args()
        if args != nil&&len(args) > 0 {
                var err error
                n,err = strconv.Atoi(args)
                if err != nil {
                        n = 300
                }
                m,err = strconv.Atoi(args)
                if err != nil {
                        m = 10000
                }
        } else {
                n = 300
                m=10000
        }
        fmt.Println("n=", n,"m=",m)
       
        //2.创建队列/channel
        //用于结束.go没有join之类的等待同步函数
        result := make(chan int)
        chs := make([]chan int,n)
        for i := 0; i < n; i++ {
                chs = make(chan int)
                //5.启动节点(创建协程)
                go node(i,chs,result)
        }
       
       

//4.初始化消息
//go的channel写也是阻塞的
for i := 0; i < m; i++ {
        //fmt.Println("put msg ", i," intochannel 0")
        chs <- i
}

//等待结束
<-result
}

//测试结果

/*
192.168.6.150
-bash-3.2$ go build ring.go
-bash-3.2$ time ./ring 3000 100
n= 3000 m= 100
final msg send back

real    0m0.356s
user    0m0.229s
sys   0m0.020s
-bash-3.2$ time go run ./ring.go 3000 100
n= 3000 m= 100
final msg send back

real    0m0.919s
user    0m0.631s
sys   0m0.079s
-bash-3.2$
-bash-3.2$ time ./ring 10000 100
n= 10000 m= 100
final msg send back

real    0m1.113s
user    0m0.774s
sys   0m0.038s
-bash-3.2$ time go run ./ring.go 10000 100
n= 10000 m= 100
final msg send back

real    0m1.747s
user    0m1.276s
sys   0m0.093s

-bash-3.2$ time ./ring 100 10000
n= 100 m= 10000
final msg send back

real    0m0.692s
user    0m0.493s
sys   0m0.004s
-bash-3.2$
-bash-3.2$ time go run ./ring.go 100 10000
n= 100 m= 10000
final msg send back

real    0m1.329s
user    0m0.903s
sys   0m0.074s
-bash-3.2$
-bash-3.2$ time go run ./ring.go 300 10000
n= 300 m= 10000
final msg send back

real    0m2.628s
user    0m1.924s
sys   0m0.073s
-bash-3.2$ time ./ring 300 10000
n= 300 m= 10000
final msg send back

real    0m1.922s
user    0m1.505s
sys   0m0.018s

*/
页: [1]
查看完整版本: [练习]go版的击鼓传花