在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随机选择一个进行执行。