以前用golang做并发处理的时候,很是粗暴,就是利用golang的高级性能,直接fork一个任务,来处理请求,最典型的就是直接 go func,当时是因为用http和socket没觉得什么,今天再次看golang的goroutine的时候,发现这几天写的程序有些问题。比如用goroutine的时候,同步堵塞。太快了,需要堵堵,不然我没法判断逻辑了。
原文:http://www.jb51.cc/article/p-vydfpung-ng.html
来个简单的例子:
//xiaorui.cc package main import ( "fmt" "runtime" "time" ) var a int = 1 func main() { runtime.GOMAXPROCS(runtime.Numcpu()) go sheep(1) // go sheep(2) time.Sleep(time.Millisecond) fmt.Println("end",a) } func sheep(i int) { for ; ; i += 1 { fmt.Println(i,"个�丝") a+=1 } }
原文:xiaorui.cc
这个是打印�丝的数量,golang下的并发直接go 函数就可以了,但是单纯的go的话,他会因为后续的main主函数的任务结束,而结束 。 对于main来说,我已经运行完了,刚才go出去的任务,爱咋咋地。。。 他就这么不负责不管了。 其实这里咱们先不说用golang的解决的方法, 其实可以在结束的时候做个判断,比如每次go完了后,不管成功或者失败都会给一个全局变量加个数或者赋予一个值。 然后再main里面做一个判断,接着是堵塞这个判断,只有if 匹配后,才推出程序。
这个是土方法,其实咱们可以用golang自带的channel,这个东西初级的想法,可以解决上面的问题。 他在golang里面代表了通信官的作用。
//xiaorui.cc package main import ( "fmt" ) var a string var c = make(chan int,10) func f() { fmt.Println("f 函数运行了") a = "hello,world" c <- 0 } func main() { fmt.Println("先让f这个函数先跑着") go f() <-c fmt.Println("我这里取得了a的值",a) }
channel有四个操作:
创建:c = make(chan int)
发送:c <- 1
提取:i <- c
关闭:close(c)
里面的10是buffered channels,指定channel的缓冲大小
ch := make(chan type,value)
value == 0 !无缓冲(阻塞)
value > 0 !缓冲(非阻塞,直到value个元素)
大家可以跑跑下面的例子,加深下channel的理解 。
package main import ( "fmt" "time" ) func main() { go say("world") say("hello") fmt.Println("---------------1") a := []int{7,2,8,-9,4,0} c := make(chan int) go sum(a[:len(a)/2],c) go sum(a[len(a)/2:],c) x,y := <-c,<-c // receive from c fmt.Println(x,y,x+y) fmt.Println("---------------2") c2 := make(chan int,2) c2 <- 1 c2 <- 2 fmt.Println(<-c2) fmt.Println(<-c2) fmt.Println("---------------3") c3 := make(chan int,10) go fibonacci(cap(c3),c3) for i := range c3 { fmt.Println(i) } fmt.Println("---------------4") c4 := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c4) } quit <- 0 }() fibonacci2(c4,quit) fmt.Println("---------------5") tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick. ") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } } func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func sum(a []int,c chan int) { sum := 0 for _,v := range a { sum += v } c <- sum // send sum to c } func fibonacci(n int,c chan int) { x,y := 0,1 for i := 0; i < n; i++ { c <- x x,y = y,x+y } close(c) } func fibonacci2(c,quit chan int) { x,1 for { select { case c <- x: x,x+y case <-quit: fmt.Println("quit") return } } }
对于golang的同步问题,不仅可以用channel来解决,也可以用golang的另一个包 sync来解决。
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) } for i := 0; i < 100; i++ { go done(&wg) } wg.Wait() fmt.Println("exit") } func add(wg sync.WaitGroup) { wg.Add(1) } func done(wg *sync.WaitGroup) { wg.Done() }
sync.WaitGroup只有3个方法,Add(),Done(),Wait()。其中Done()是Add(-1)的别名。简单的来说,使用Add()添加计数,Done()减掉一个计数,计数不为0,阻塞Wait()的运行。
python下的gevent里面的协程机制和golang差不多的,有时间让他们对比下,看看gevent比golang的goroutine相差多少。
遇到的问题,这个是因为本身网络就不稳定引起的,为了更友好的显示数据,需要做好更好的defer异常的处理
goroutine 431 [select]: net/http.(*Transport).getConn(0x187491e0,0x189590a0,0x0,0x0) /root/go/src/pkg/net/http/transport.go:424 +0x1e9 net/http.(*Transport).RoundTrip(0x187491e0,0x1895a000,0x1894a794,0x0) /root/go/src/pkg/net/http/transport.go:182 +0x26b net/http.send(0x1895a000,0xb771e9c8,0x187491e0,...) /root/go/src/pkg/net/http/client.go:168 +0x2b3 net/http.(*Client).send(0x83f3d30,0x11,0x8064f6a,0x4) /root/go/src/pkg/net/http/client.go:100 +0xb0 net/http.(*Client).doFollowingRedirects(0x83f3d30,0x825213c,...) /root/go/src/pkg/net/http/client.go:294 +0x50e net/http.(*Client).Get(0x83f3d30,0x8217e38,...) /root/go/src/pkg/net/http/client.go:248 +0x98 net/http.Get(0x8217e38,0x0) /root/go/src/pkg/net/http/client.go:225 +0x4d main.f(0x1871c210) /ceshi/httpget.go:14 +0x30 created by main.main /ceshi/httpget.go:25 +0xe5原文链接:https://www.f2er.com/go/191048.html