Go 并发

传统的并发是通过进程、线程、I/O多路复用来实现,现在越来越多的语言支持基于协程(coroutine)的并发模型。如:Actor模型的Akka/Erlang、CSP模型的Goroutine/Go。

操作系统层的两个比较知名的“协程”接口族分别是:Microsoft Windows的fiber和POSIX的ucontext(linux实现该接口)。

Go语言中的并发程序可以用两种手段来实现:goroutine/channel、多线程共享内存(传统并发模型)。

 一、Goroutines和Channels

在Go语言中,当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们称之为main goroutine。新的goroutine会用go语句来创建。

func main() {
    go spinner(100 * time.Millisecond)
    const n = 45
    fibN := fib(n) // slow
    fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)
}

func spinner(delay time.Duration) {
    for {
        for _, r := range `-\|/` {
            fmt.Printf("\r%c", r)
            time.Sleep(delay)
        }
    }
}

func fib(x int) int {
    if x < 2 {
        return x
    }
    return fib(x-1) + fib(x-2)
}

如果说goroutine是Go语言程序的并发体的话,那么channels则是他们之间的通信机制。channel可以让一个goroutine通过它给另一个goroutine发送值信息。

每个channel都有一个特殊的类型,也就是channels可发送数据的类型。一个可以发送int类型数据的channel一般写作chan int。

使用内置的make函数,我们可以创建channel:

ch := make(chan int) // ch has type 'chan int'

一个channel有发送和接收两个主要操作,都使用<-运算符。如:

ch <- x  // a send statement
x = <-ch // a receive expression in an assignment statement
<-ch     // a receive statement; result is discarded

channel还支持close操作,用于关闭channel,随后对基于该channel的任何发送操作都将导致panic异常。

对一个已经被close过的channel进行接收操作依然可以接收到之前已经成功发送的数据,如果channel中已经没有数据的话将产生一个零值的数据。

channel分为有缓存和无缓存两种,通过make创建时指定第二个整型参数,大于零时为带缓存的channel。

close(ch) // close channel

ch = make(chan int)    // unbuffered channel
ch = make(chan int, 0) // unbuffered channel
ch = make(chan int, 3) // buffered channel with capacity 3

  

 

 

待续...

posted @ 2018-07-03 10:17  木子锤  阅读(191)  评论(0编辑  收藏  举报