goroutines以及channel

goroutines

goroutines并不对应着操作系统中的线程,它可以由多个线程来执行 gorouinte 之间又不像进程之间那样,使用独立的内存空间,它们使用共享的内存空间,因此它们存在读写同步的问题,使用go的channel。

gc-compiler对应着是真正的goroutines,每个都对应着一个或若干个线程,而gccgo则是为每一个goroutine建立一个线程。
不要试图用print语句来显示多个进程间的真实顺序,因为print的延迟会导致显示的不是真正的顺序

channel

  • 非缓存的channel
    channel是无法暂时混存数据,因此发送端会被阻塞,除非接受端从channel中接收数据
    非缓存的channel很适合用于多个goroutines之间同步
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package main
    import (
    “fmt” )
    func f1(in chan int) {
    fmt.Println(<-in)
    }
    func main() {
    out := make(chan int)
    out <- 2
    go f1(out)
    }

这段代码中总会出现deadlock作用。因为main这个goroutine运行到out<-2时,因为是非缓存的,所以阻塞了,后面的f1还没有启动,因此所有的goroutine都进入了死亡状态

  • select和channel的使用
1
2
3
4
5
6
7
8
9

select {
case u:= <- ch1:
...
case v:= <- ch2:
...
...
default: // no value ready to be received
... }

相当于是在从几个goroutine中选择已经有结果了的进行处理,如果外面加上一个无限循环的话,就能够达到不断处理的效果了
针对以上这个代码
如果有多个通道已经ready了的话,就随机从中选出一个
如果没有ready的话它会等待
如果添加了default的话,在没有一个是ready的情况下将会执行default的代码

  • 缓存的channel
    cap函数可以得到buffe的大小
    发送端当且仅当channel满了的时候阻塞,接受端当且仅当channel空了的时候阻塞

  • 利用goroutines和channel来进行并行编程
    可以讲channel当作一个信号量,用于锁住资源
    利用for循环的并行化

    1
    2
    3
    4
    5
    for i, v := range data {
    go func (i int, v float64) {
    }
    doSomething(i, v)
    ... } (i, v)
  • 利用缓存的channel来实现信号量
    channel的容量是我们想要进行同步的资源个数
    channel的现有长度是现在被占用的资源个数
    channel的容量-长度是现在可用的资源的个数

  • channel factory 模式
    可以在主goroutine中创建channel然后传入函数中,也可以在函数中创建channel然后返回到调用它的goroutine中来实现同步

  • 指定channel的类型只发送或只接收

    1
    2
    var send_only chan<- int // channel can only receive data 
    var recv_only <-chan int // channel can only send data
分享到