golang并发一

在go里,每一个并发执行的活动称为goroutine。go有两种并发编程风格,通信顺序进程模式(基于channel),共享内存。

在go里面创建一个goroutine特别简单,只需在函数前面添加关键字go即可

func f()  {
    //TODO ADD CODE HERE
}
func main()  {
    go f()
}

go f()即创建了一个goroutine,并且并发执行函数f

通信顺序进程模式

通道

通道是goroutine之间的连接,可以让一个goroutine将值发送给另一个goroutine。每个通道都有一个具体的类型,一个int型的通道写作chan int。

通道有三个操作:发送,接收,关闭(不常用)。

缓冲通道有一个缓冲队列,接收操作从队列的头部移除一个元素,发送操作在队列的尾部插入一个元素,如果队列已满,则发送操作阻塞,队列为空,则接受操作为空。

当通道容量为0时,发送操作会阻塞,直到另一个goroutine进行接收操作,这时值传送完成,两个goroutine继续工作。接收操作同理。

代码示例

channel := make(chan int)
channel := make(chan struct{},3)
channel <- 1
_ = <- channel

一下代码我们实现一个生产者和消费者示例:

func main() {
    channel := make(chan int, 10)
    for i := 0; i < 10; i++ {
        go procedur(channel)
    }
    for i := 0; i < 12; i++ {
        go consumer(channel, i)
    }
    for {
        time.Sleep(time.Second)
    }

}

//生产者 只可以进行发送操作
func procedur(channel chan<- int) {
    for i := 0; i < 101; i++ {
        channel <- i
        i %= 100
        time.Sleep(time.Millisecond * 100)
    }
}

//生产者 只可以进行接收操作
func consumer(channel <-chan int, id int) {
    for {
        v := <-channel
        fmt.Println(id, v)
        time.Sleep(time.Millisecond * 200)
    }
}

模仿了十个生产者和十二个消费者的情况

select 多路复用

select 语句类似switch 语句,有一系列情况和一个可选的默认分支,每一个情况指定一次通信和关联的代码块。

以下势力为随机生成数字以及输出的示例

channel := make(chan int, 10)
for i := 0; i < 100; i++ {
    select {
        case v := <-channel:
            fmt.Println(v)
        case channel <- i:

    }
}

需要注意的是,如果有多个情况同时满足,select随机选择一个进行执行。