简答说 你在一个关闭的通道发消息
那么你发送之前 检查一下 如果已经关闭了 就不发了 【治标不治本 先试一试】
奇怪的是WIN10跑他的代码 没有问题!!树莓派run的话 一会就嗝屁!!!
package main
import (
"fmt"
"sync"
"time"
)
func main() {
jobs := make(chan int)
var wg sync.WaitGroup
go func() {
time.Sleep(time.Second * 3)
close(jobs)
}()
go func() {
for i := 0; ; i++ {
jobs <- i
fmt.Println("produce:", i)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for i := range jobs {
fmt.Println("consume:", i)
}
}()
wg.Wait()
}
它修改后的代码
package main
import (
"fmt"
"sync"
"time"
)
func main() {
jobs := make(chan int)
timeout := make(chan bool)
var wg sync.WaitGroup
go func() {
time.Sleep(time.Second * 3)
timeout <- true
}()
go func() {
for i := 0; ; i++ {
select {
case <-timeout:
close(jobs)
return
default:
jobs <- i
fmt.Println("produce:", i)
}
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for i := range jobs {
fmt.Println("consume:", i)
}
}()
wg.Wait()
}
主线程为了等待goroutine都运行完毕,
不得不在程序的末尾使用time.Sleep()
来睡眠一段时间,等待其他线程充分运行。
对于简单的代码,100个for循环可以在1秒之内运行完毕,time.Sleep()
也可以达到想要的效果。
但是对于实际生活的大多数场景来说,1秒是不够的,
并且大部分时候我们都无法预知for循环内代码运行时间的长短。
这时候就不能使用time.Sleep()
来完成等待操作了。
管道在这里显得有些大材小用,因为它被设计出来不仅仅只是在这里用作简单的同步处理,在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for
循环,也要申请同样数量大小的管道出来,对内存也是不小的开销。
对于这种情况,go语言中有一个其他的工具sync.WaitGroup
能更加方便的帮助我们达到这个目的。
WaitGroup
对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait()
用来控制计数器的数量。
Add(n)
把计数器设置为n
,
Done()
每次把计数器-1
,
wait()
会阻塞代码的运行,直到计数器地值减为0
。
继续看前面的文章
1----
go func() {
time.Sleep(time.Millisecond * 1)
close(jobs)
}()
修改为这样 更快出现问题 概率死机
而 如果 不要上面这个关闭函数
永远不会死机
2---用途
3---解决文章开头我们的问题
也就是自己关闭 外部发消息过来 生产者关闭