go 速学 - 15 - 并发
目录
摘要
goroutine,Channel 作用,单向与双向 channel,生产者与消费者模式,缓存与无缓存 channel,同步与异步,WaitGroup,Select, timeout
并发
goroutine
使用 goroutine
语法为 go 方法名()
import "time"
func test01() {
fmt.Println("test01...")
}
go test01() //test01...
time.Sleep(1 * time.Second)
以上如果不调用 Sleep() 方法则 main() 方法结束后程序就结束了,其它线程无法得到执行的机会
Channel
概述
Channel
是引用类型Channel
可以用于阻塞线程- 可以设置缓存,缓存默认为
0
- 缓存没有填满之前不会阻塞
Channle
的主要作用是消息传递和同步
建立 Channel
语法
- 创建 Channel
make(chan type, cacheSize)
- 关闭 Channel
close(ch)
- 向 Channel 中存入数据
ch<-data
- 从 Channel 中读取数据
<-ch
单向 Channel
默认创建的 Channel 为双向的,也可以创建只读或只写的单向 Channel。
单向 Channel 一般用于消息传递。
只写 Channel
var ch1 chan<- int
只读 Channel
var ch2 <-chan int
生产者,消费者示例
func producer(queue chan<- int) {
for i := 0; i < 10; i++ {
queue <- i
fmt.Println("send:", i)
}
close(queue)
}
func consumer(queue <-chan int) {
for i := 0; i < 10; i++ {
v := <-queue
fmt.Println("receive:", v)
}
}
queue := make(chan int, 1)
go producer(queue)
go consumer(queue)
time.Sleep(1 * time.Second)
使用没有缓存的 Channel
没有缓存的 Channel
又称为同步 Channel
,主要用于同步操作。
接收方会一直阻塞直到有数据到来。如果 channel
是无缓冲的,发送方会一直阻塞直到接收方将数据取出。
func test02(ch chan bool) {
fmt.Println("test02...")
fmt.Println("waiting...")
ch <- true
close(ch)
}
ch := make(chan bool)
go test02(ch)
//以下代码中 ch 阻塞线程等待输入,直到 test02()中 true被输入到 channel 中
<-ch //test02... waiting...
ch = make(chan bool)
go test02(ch)
for v := range ch {
fmt.Println(v)
}
<-ch //test02...waiting...true
使用有缓存的 Channel
接收方会一直阻塞直到有数据到来。如果 channel
带有缓冲区,发送方会一直阻塞直到数据被拷贝到缓冲区;如果缓冲区已满,则发送方只能在接收方取走数据后才能从阻塞状态恢复。
func test05(ch chan bool) {
fmt.Println("test05...")
fmt.Println("waiting test05...")
ch <- true
fmt.Println("waiting 01...")
fmt.Println("waiting 02...")
fmt.Println("waiting 03...")
close(ch)
}
ch = make(chan bool, 10)
go test05(ch)
d := <-ch
fmt.Println("d", d) //test05... waiting test05... waiting01 waiting02 waiting03 true
多线程同步
开启多线程
开启多线程使用如下代码
import "runtime"
runtime.GOMAXPROCS(runtime.NumCPU())
使用 Channel 同步
func test03(ch chan bool, index int) {
a := 1
for i := 0; i < 1000; i++ {
a += i
}
fmt.Println("test03", index, a)
ch <- true
}
ch = make(chan bool, 10)
for i := 0; i < 10; i++ {
go test03(ch, i) //向 Channel 写10次
}
for i := 0; i < 10; i++ {
<-ch //从 Channel 读10次
}
使用 WaitGroup 同步
func test04(wg *sync.WaitGroup, index int) {
a := 1
for i := 0; i < 1000; i++ {
a += i
}
fmt.Println("test04", index, a)
wg.Done()
}
wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go test04(&wg, i)
}
wg.Wait()
Select
概述
- 可按随机顺序同时处理多个
channel
- 可用
空 channel
阻塞main
线程 - 可设置
timout
时间
使用 Select
定义三个 Channel
c1, c2 := make(chan int), make(chan string) //进行数据传输
o := make(chan bool) //进行阻塞
定义 goroutine
go func() {
for {
select {
case v, ok := <-c1:
if !ok {
o <- true
break
}
fmt.Println("c1", v)
case v, ok := <-c2:
if !ok {
o <- true
break
}
fmt.Println("c2", v)
}
}
}()
c1 <- 1
c2 <- "hi"
c1 <- 2
c2 <- "hello"
close(c1)
close(c2)
<-o
//c1 1 -> c2 hi -> c1 2 -> c2 hello
设置 Timeout
select {
case <-time.After(2 * time.Millisecond):
fmt.Println("timeout")
}
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。