个人对于golang的goroutine并发处理任务时的理解
u010412301 · · 1434 次点击 · · 开始浏览个人对于golang的goroutine并发处理任务时的理解
原文:http://rfyiamcool.blog.51cto.com/1030776/1381686
以前用golang做并发处理的时候,很是粗暴,就是利用golang的高级性能,直接fork一个任务,来处理请求,最典型的就是直接 go func,当时是因为用http和socket没觉得什么,今天再次看golang的goroutine的时候,发现这几天写的程序有些问题。比如用goroutine的时候,同步堵塞。太快了,需要堵堵,不然我没法判断逻辑了。
来个简单的例子:
//xiaorui.ccpackage 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}}
wKiom1MtuyqyA9WiAABz1gj0xqw874.jpg
原文:xiaorui.cc
这个是打印屌丝的数量,golang下的并发直接go 函数就可以了,但是单纯的go的话,他会因为后续的main主函数的任务结束,而结束 。 对于main来说,我已经运行完了,刚才go出去的任务,爱咋咋地。。。 他就这么不负责不管了。 其实这里咱们先不说用golang的解决的方法, 其实可以在结束的时候做个判断,比如每次go完了后,不管成功或者失败都会给一个全局变量加个数或者赋予一个值。 然后再main里面做一个判断,接着是堵塞这个判断,只有if 匹配后,才推出程序。
这个是土方法,其实咱们可以用golang自带的channel,这个东西初级的想法,可以解决上面的问题。 他在golang里面代表了通信官的作用。
//xiaorui.ccpackage main
import("fmt")var a stringvar 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!")returndefault:
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 :=0for _, v := range a {
sum += v
}
c <- sum // send sum to c}
func fibonacci(n int, c chan int){
x, y :=0,1for i :=0; i < n; i++{
c <- x
x, y = y, x+y
}
close(c)}
func fibonacci2(c, quit chan int){
x, y :=0,1for{select{case c <- x:
x, y = y, x+y
case<-quit:
fmt.Println("quit")return}}}
对于golang的同步问题,不仅可以用channel来解决,也可以用golang的另一个包 sync来解决。
package main
import("fmt""sync")
func main(){var wg sync.WaitGroupfor 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异常的处理。
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
个人对于golang的goroutine并发处理任务时的理解
原文:http://rfyiamcool.blog.51cto.com/1030776/1381686
以前用golang做并发处理的时候,很是粗暴,就是利用golang的高级性能,直接fork一个任务,来处理请求,最典型的就是直接 go func,当时是因为用http和socket没觉得什么,今天再次看golang的goroutine的时候,发现这几天写的程序有些问题。比如用goroutine的时候,同步堵塞。太快了,需要堵堵,不然我没法判断逻辑了。
来个简单的例子:
//xiaorui.ccpackage 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}}
wKiom1MtuyqyA9WiAABz1gj0xqw874.jpg
原文:xiaorui.cc
这个是打印屌丝的数量,golang下的并发直接go 函数就可以了,但是单纯的go的话,他会因为后续的main主函数的任务结束,而结束 。 对于main来说,我已经运行完了,刚才go出去的任务,爱咋咋地。。。 他就这么不负责不管了。 其实这里咱们先不说用golang的解决的方法, 其实可以在结束的时候做个判断,比如每次go完了后,不管成功或者失败都会给一个全局变量加个数或者赋予一个值。 然后再main里面做一个判断,接着是堵塞这个判断,只有if 匹配后,才推出程序。
这个是土方法,其实咱们可以用golang自带的channel,这个东西初级的想法,可以解决上面的问题。 他在golang里面代表了通信官的作用。
//xiaorui.ccpackage main
import("fmt")var a stringvar 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!")returndefault:
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 :=0for _, v := range a {
sum += v
}
c <- sum // send sum to c}
func fibonacci(n int, c chan int){
x, y :=0,1for i :=0; i < n; i++{
c <- x
x, y = y, x+y
}
close(c)}
func fibonacci2(c, quit chan int){
x, y :=0,1for{select{case c <- x:
x, y = y, x+y
case<-quit:
fmt.Println("quit")return}}}
对于golang的同步问题,不仅可以用channel来解决,也可以用golang的另一个包 sync来解决。
package main
import("fmt""sync")
func main(){var wg sync.WaitGroupfor 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异常的处理。