一、缓冲设置
无缓冲
func testChan() {
ch := make(chan int) // 不带第二个参数代表无缓冲,即如果放入了一个数据ch <- task 若没有取出数据的线程task := <-ch,线程将会挂起等待直到数据被取出
//启动固定数量的worker
for i := 0; i < 5; i++ {
go worker(ch) // go代表起一个协程并行运行,此处循环多少个,代表起了多少个协程执行任务
}
//发送任务给worker
taskList:= []int{88, 99, 111, 222, 333, 555, 666, 234, 544, 777, 888, 265, 152}
for _, task := range taskList{
ch <- task // 无缓冲时每放入一个数据将会等待数据被拿走后循环才能继续
}
fmt.Println("process completed!")
time.Sleep(time.Duration(2) * time.Second) // 等待子线程打印处理完成
}
func worker(ch chan int) {
for {
//接受任务
task := <-ch // 取出数据
fmt.Println("worker:process task = %d", task)
}
}
执行结果:
此处有5个协程在处理任务,各线程包括主线程执行顺序不能保证,所以此处主线程先分发完数据(数据已被子线程取完但没来得及运行到打印部分)
[Running] go run "c:\Code\Go\src\test\main.go"
worker:process task = %d 222
worker:process task = %d 555
worker:process task = %d 88
worker:process task = %d 111
worker:process task = %d 333
worker:process task = %d 99
worker:process task = %d 234
worker:process task = %d 666
process completed!
worker:process task = %d 544
worker:process task = %d 888
worker:process task = %d 777
worker:process task = %d 265
worker:process task = %d 152
[Done] exited with code=0 in 7.046 seconds
有缓冲 设置缓冲队列为10
ch := make(chan int, 10)
执行结果:
由于缓冲队列为10,可以看到生产队列远没有无缓冲时易被阻塞,不必等协程取数据,可以往队列中连续放置10个数据,很快主线程就先执行完毕
[Running] go run "c:\Code\Go\src\test\main.go"
process completed!
worker:process task = %d 88
worker:process task = %d 333
worker:process task = %d 555
worker:process task = %d 99
worker:process task = %d 544
worker:process task = %d 111
worker:process task = %d 888
worker:process task = %d 265
worker:process task = %d 152
worker:process task = %d 777
worker:process task = %d 666
worker:process task = %d 222
worker:process task = %d 234
[Done] exited with code=0 in 4.734 seconds
二、close使用
func main() {
ch1 := make(chan int, 5)
ch2 := make(chan int, 5)
close(ch2) // 关闭ch2
go func() { // 启动协程等待channel收到数据
select {
case <-ch1: // ch1无数据输入一直阻塞
log.Printf("case ch1 is here\n")
case _, ok := <-ch2: // ch2虽然无数据输入,但是ch2通道close了,这里依然能触发,但是ok为false,若是正常输入,这个ok值会为true
log.Printf("case ch2 is here, ok = %v\n", ok)
ch1Result := <-ch1 // ch1无数据输入一直阻塞 证明close通道后,chan不会被阻塞
log.Printf("case ch1 is here ch1Result = %d\n", ch1Result)
}
}()
time.Sleep(time.Duration(5) * time.Second)
log.Printf("main is here\n")
}
执行结果:
[Running] go run "c:\Code\Go\src\test\main.go"
2021/04/07 14:49:02 case ch2 is here, ok = false
2021/04/07 14:49:07 main is here
[Done] exited with code=0 in 8.771 seconds
应用:可使用close chan来获取结束信号