个人对于golang的goroutine并发处理任务时的理解

来源:互联网 发布:silverlining源码osg 编辑:程序博客网 时间:2024/05/28 18:43

个人对于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 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 := &lt;-c, &lt;-c // receive from c                                                                                                                                                                                                                                              fmt.Println(x, y, x+y)                                                                                                                                                                                                                                              fmt.Println("---------------2")                                                                                                                                                                                                                                              c2 := make(chan int, 2)    c2 &lt;- 1    c2 &lt;- 2    fmt.Println(&lt;-c2)    fmt.Println(&lt;-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 &lt; 10; i++ {            fmt.Println(&lt;-c4)        }        quit &lt;- 0    }()    fibonacci2(c4, quit)                                                                                                                                                                                                                                              fmt.Println("---------------5")    tick := time.Tick(100 * time.Millisecond)    boom := time.After(500 * time.Millisecond)    for {        select {        case &lt;-tick:            fmt.Println("tick. ")        case &lt;-boom:            fmt.Println("BOOM!")            return        default:            fmt.Println("    .")            time.Sleep(50 * time.Millisecond)        }    }                                                                                                                                                                                                                                          }                                                                                                                                                                                                                                          func say(s string) {    for i := 0; i &lt; 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 &lt;- sum // send sum to c}                                                                                                                                                                                                                                          func fibonacci(n int, c chan int) {    x, y := 0, 1    for i := 0; i &lt; n; i++ {        c &lt;- x        x, y = y, x+y    }   close(c)}                                                                                                                                                                                                                                          func fibonacci2(c, quit chan int) {    x, y := 0, 1    for {        select {        case c &lt;- x:            x, y = y, x+y        case &lt;-quit:            fmt.Println("quit")            return        }    }}

对于golang的同步问题,不仅可以用channel来解决,也可以用golang的另一个包 sync来解决。

package mainimport (    "fmt"    "sync")func main() {    var wg sync.WaitGroup    for i := 0; i &lt; 100; i++ {        wg.Add(1)    }    for i := 0; i &lt; 100; i++ {        go done(&amp;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异常的处理。

原创粉丝点击