Golang超全面讲解并发
简介
本文将介绍Golang并发相关的知识,包括如何使用goroutine和channel等内容。并发编程是Golang的一大特色,也是Golang广泛应用的原因之一。本文可以帮助有一定Golang基础的开发者更好的理解并发编程的概念和实现。
Goroutine
Goroutine是Golang并发编程的关键,每个Goroutine是一条轻量级的线程,它可以与其他Goroutine并行执行。与传统线程不同,Goroutine具有以下特点:
- 一个程序可以创建成千上万个Goroutine而不会导致资源瓶颈;
- Goroutine采用多路复用技术实现,可以高效地利用CPU资源;
- Goroutine之间的切换比线程更快,切换的代价几乎可以忽略不计;
- Goroutine之间的通信可以通过channel实现,不需要使用锁等复杂的同步机制。
通过在函数前加上"go"关键字即可创建一个Goroutine,例如:
func test() {
// do something
}
go test()
Channel
Channel是Golang并发编程中非常重要的组件,它用于在Goroutine之间传递数据。Channel具有以下特点:
- 可以保证并发安全;
- 可以限制Goroutine的并发度;
- 可以实现同步机制,一个Goroutine可以等待另一个Goroutine的执行结果后再继续执行。
Channel通过make函数创建,并指定数据类型和缓冲区大小,例如:
ch := make(chan int, 10)
上面创建了一个缓冲区大小为10的int型channel。使用channel的发送和接收操作可以通过<-符号实现,例如:
ch <- 10 // 发送数据
x := <-ch // 接收数据
如果希望等待Goroutine执行结果后再继续执行,可以使用channel的阻塞操作,例如:
ch := make(chan string)
go func() {
// do something
ch <- "result"
}()
res := <-ch // 阻塞等待结果
// do something with res
示例
示例1:Goroutine和Channel基本使用
下面的示例演示了如何使用Goroutine和Channel,实现一条生产-消费模型的数据处理流程。
package main
import (
"fmt"
"time"
)
func producer(ch chan int, id int) {
for i := 0; i < 10; i++ {
ch <- i
fmt.Printf("Producer %d: send %d\n", id, i)
}
close(ch)
}
func consumer(ch chan int, id int) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Printf("Consumer %d: receive %d\n", id, v)
}
}
func main() {
ch := make(chan int)
go producer(ch, 1)
go producer(ch, 2)
go consumer(ch, 1)
go consumer(ch, 2)
time.Sleep(time.Second)
}
输出结果如下:
Producer 1: send 0
Producer 2: send 0
Consumer 2: receive 0
Consumer 1: receive 0
Producer 1: send 1
Producer 2: send 1
Consumer 1: receive 1
Consumer 2: receive 1
Producer 1: send 2
Producer 2: send 2
Consumer 2: receive 2
Consumer 1: receive 2
Producer 1: send 3
Producer 2: send 3
Consumer 2: receive 3
Consumer 1: receive 3
Producer 1: send 4
Producer 2: send 4
Consumer 1: receive 4
Consumer 2: receive 4
Producer 1: send 5
Producer 2: send 5
Consumer 2: receive 5
Consumer 1: receive 5
Producer 2: send 6
Producer 1: send 6
Consumer 1: receive 6
Consumer 2: receive 6
Producer 1: send 7
Producer 2: send 7
Consumer 2: receive 7
Consumer 1: receive 7
Producer 1: send 8
Producer 2: send 8
Consumer 1: receive 8
Consumer 2: receive 8
Producer 1: send 9
Producer 2: send 9
Consumer 1: receive 9
Consumer 2: receive 9
在本示例中,使用了两个Producer Goroutine和两个Consumer Goroutine。两个Producer Goroutine向同一个channel发送数据,两个Consumer Goroutine从同一个channel接收数据。由于channel是安全的,因此Goroutine之间不需要进行加锁等复杂的同步机制。
示例2:使用Select实现超时机制
下面的示例演示了如何使用Select语句实现一个超时机制,即等待一定时间后超时退出。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
timeout := time.After(time.Second * 3)
go func() {
time.Sleep(time.Second * 5)
ch <- 1
}()
select {
case <-ch:
fmt.Println("Received data")
case <-timeout:
fmt.Println("Timeout")
}
}
输出结果为:
Timeout
在本示例中,首先创建了一个缓冲区大小为1的int型channel,然后通过time.After函数创建一个超时channel。使用Goroutine模拟一个耗时的操作,睡眠5秒后向channel发送数据。使用Select语句并同时监听数据channel和超时channel,当其中一个channel发生事件时,输出相应的信息。在本示例中,由于超时时间已经到达但是数据channel还没有收到数据,因此输出"Timeout"。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Golang超全面讲解并发 - Python技术站