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

前端之家收集整理的这篇文章主要介绍了对于golang的goroutine并发处理任务时的理解前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_403_0@以前用golang做并发处理的时候,很是粗暴,就是利用golang的高级性能,直接fork一个任务,来处理请求,最典型的就是直接 go func,当时是因为用http和socket没觉得什么,今天再次看golang的goroutine的时候,发现这几天写的程序有些问题。比如用goroutine的时候,同步堵塞。太快了,需要堵堵,不然我没法判断逻辑了。

@H_403_0@

@H_403_0@原文:http://www.jb51.cc/article/p-vydfpung-ng.html

@H_403_0@来个简单的例子:

@H_403_0@

//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
       }
   }
@H_403_0@

wKiom1MtuyqyA9WiAABz1gj0xqw874.jpg

@H_403_0@原文:xiaorui.cc

@H_403_0@

@H_403_0@这个是打印�丝的数量,golang下的并发直接go 函数就可以了,但是单纯的go的话,他会因为后续的main主函数的任务结束,而结束 。 对于main来说,我已经运行完了,刚才go出去的任务,爱咋咋地。。。 他就这么不负责不管了。 其实这里咱们先不说用golang的解决方法, 其实可以在结束的时候做个判断,比如每次go完了后,不管成功或者失败都会给一个全局变量加个数或者赋予一个值。 然后再main里面做一个判断,接着是堵塞这个判断,只有if 匹配后,才推出程序。

@H_403_0@

@H_403_0@这个是土方法,其实咱们可以用golang自带的channel,这个东西初级的想法,可以解决上面的问题。 他在golang里面代表了通信官的作用。

@H_403_0@

//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)
}
@H_403_0@

@H_403_0@channel有四个操作:

@H_403_0@

@H_403_0@创建:c = make(chan int)

@H_403_0@发送:c <- 1

@H_403_0@提取:i <- c

@H_403_0@关闭:close(c)

@H_403_0@里面的10是buffered channels,指定channel的缓冲大小

@H_403_0@

@H_403_0@ ch := make(chan type,value)

@H_403_0@ value == 0 !无缓冲(阻塞)

@H_403_0@ value > 0 !缓冲(非阻塞,直到value个元素)

@H_403_0@

@H_403_0@大家可以跑跑下面的例子,加深下channel的理解 。

@H_403_0@

@H_403_0@

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
        }
    }
}
@H_403_0@

@H_403_0@

@H_403_0@对于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()
}
@H_403_0@

@H_403_0@sync.WaitGroup只有3个方法,Add(),Done(),Wait()。其中Done()是Add(-1)的别名。简单的来说,使用Add()添加计数,Done()减掉一个计数,计数不为0,阻塞Wait()的运行。

@H_403_0@

@H_403_0@python下的gevent里面的协程机制和golang差不多的,有时间让他们对比下,看看gevent比golang的goroutine相差多少。

@H_403_0@

@H_403_0@

@H_403_0@

@H_403_0@遇到的问题,这个是因为本身网络就不稳定引起的,为了更友好的显示数据,需要做好更好的defer异常的处理

@H_403_0@

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

猜你在找的Go相关文章