版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33781658/article/details/84503111
我们先来这么一段代码
func main() {
channel := make(chan int)
for i := 0; i < 5; i++ {
produce(channel, i)
}
for i := 0; i < 5; i++ {
consume(channel, i)
}
select {}
}
func produce(channel chan int, i int) {
channel <- i
fmt.Println("生产了", i)
}
func consume(channel chan int, i int) {
<-channel
fmt.Println("消费了", i)
}
这里的运行结果是
fatal error: all goroutines are asleep - deadlock!
也就是死锁了
为什么呢 我们来分析一下
在第一次进入produce的时候
直接就使用channel通道发送了一个i
而此时,根本没有其他的go程来进行接收
而且下面的接收也是在主线程
那么肯定会锁死
现在我们把代码修改一下
func main() {
channel := make(chan int)
for i := 0; i < 10; i++ {
go produce(channel, i)
}
for i := 0; i < 10; i++ {
go consume(channel, i)
}
select {}
}
func produce(channel chan int, i int) {
channel <- i
fmt.Println("生产了", i)
}
func consume(channel chan int, i int) {
<-channel
fmt.Println("------消费了", i)
}
我们看一下运行结果 这里我只放一部分
------消费了 9
fatal error: all goroutines are asleep - deadlock!
生产了 1
生产了 7
生产了 0
------消费了 2
生产了 2
1.首先,生产顺序和消费顺序分别是乱序的,这是由于我们几乎同时
开启了10个生产和10个消费,很快就完成了传输和接收,
然后fmt.println这个方法其实是很慢的,所以是乱序的
2.生产和消费是乱序的,不是生产1个,消费1个,
这个其实和第一个是一个道理,这20个go程几乎是同时的
那么很快完成了传输和接收,生产和消费也就乱序了
3.出现了死锁,我们可以看一下
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
已经说的很清楚了,主线程不能出现没有case的select
所以改成for循环吧,
go程里面写没有case的select是没关系的
那么 就改成for循环
func main() {
channel := make(chan int)
for i := 0; i < 10; i++ {
go produce(channel, i)
}
for i := 0; i < 10; i++ {
go consume(channel, i)
}
for{
;
}
}
func produce(channel chan int, i int) {
channel <- i
fmt.Println("生产了", i)
}
func consume(channel chan int, i int) {
<-channel
fmt.Println("------消费了", i)
}
现在没有报错了,但是还是乱序
我们看下结果
------消费了 0
------消费了 3
------消费了 2
------消费了 6
------消费了 1
------消费了 7
生产了 2
现在,我们加入sync.Mutex
var lock sync.Mutex
func main() {
channel := make(chan int)
for i := 0; i < 10; i++ {
go produce(channel, i)
}
for i := 0; i < 10; i++ {
go consume(channel, i)
}
for {
;
}
}
func produce(channel chan int, i int) {
lock.Lock()
channel <- i
fmt.Println("生产了", i)
lock.Unlock()
}
func consume(channel chan int, i int) {
lock.Lock()
<-channel
fmt.Println("------消费了", i)
lock.Unlock()
}
运行结果: 什么都没有
现在我们来调查一下
我试了一下,不管是用两个lock还是1个lock
好像都不行
现在我们来试一下条件变量
然后就变成了这样
var cond sync.Cond
func producer(in chan<- int) {
for {
cond.L.Lock()
for len(in) == 3 {
cond.Signal()
cond.Wait()
}
num := rand.Intn(100)
fmt.Println("生产了", num)
in <- num
cond.L.Unlock()
}
}
func consumer(out <-chan int) {
for {
cond.L.Lock()
for len(out) == 0 {
cond.Signal()
cond.Wait()
}
num := <-out
fmt.Println("消费了:", num)
cond.L.Unlock()
}
}
func main() {
rand.Seed(time.Now().UnixNano())
cond.L = new(sync.Mutex)
c := make(chan int, 3)
for i := 1; i <= 5; i++ {
go producer(c)
}
for i := 1; i <= 5; i++ {
go consumer(c)
}
select {}
}
我们先从简单的开始
var cond sync.Cond
func main() {
cond.L = new(sync.Mutex)
channel := make(chan int, 3)
for i := 0; i < 5; i++ {
go produce(channel)
}
for i := 0; i < 5; i++ {
go consume(channel)
}
select {}
}
func produce(channel chan int, ) {
for i := 0; i < 100; i++ {
channel <- i
fmt.Println("生产了", i)
}
}
func consume(channel chan int) {
for i := 0; i < 100; i++ {
<-channel
fmt.Println("......消费了", i)
}
}
现在我们创建了5个go程,负责生产,5个go程负责消费
然后我们加上锁试试吧
var cond sync.Cond
func main() {
cond.L = new(sync.Mutex)
channel := make(chan int, 3)
for i := 0; i < 5; i++ {
go produce(channel)
}
for i := 0; i < 5; i++ {
go consume(channel)
}
select {}
}
func produce(channel chan int, ) {
for i := 0; i < 100; i++ {
cond.L.Lock()
if len(channel) == 3 {
cond.Broadcast()
cond.Wait()
}
channel <- i
fmt.Println("生产了", i)
cond.L.Unlock()
}
}
func consume(channel chan int) {
for i := 0; i < 100; i++ {
cond.L.Lock()
if len(channel) == 0 {
cond.Broadcast()
cond.Wait()
}
<-channel
fmt.Println("......消费了", i)
cond.L.Unlock()
}
}
还是死锁了
到底是怎么回事
我们再来一份简单代码
var cond sync.Cond
func main() {
channel := make(chan int, 3)
for i := 0; i < 5; i++ {
go produce(channel)
}
for i := 0; i < 5; i++ {
go consume(channel)
}
for {
;
}
}
func produce(channel chan int) {
for i := 0; i < 50; i++ {
channel <- i
fmt.Println("生产了", i)
}
}
func consume(channel chan int) {
for i := 0; i < 50; i++ {
num := <-channel
fmt.Println("......消费了", num)
}
}
然后我们加上锁
var cond sync.Cond
func main() {
cond.L = new(sync.Mutex)
channel := make(chan int, 3)
for i := 0; i < 5; i++ {
go produce(channel)
}
for i := 0; i < 5; i++ {
go consume(channel)
}
for {
;
}
}
func produce(channel chan<- int) {
for i := 0; i < 50; i++ {
cond.L.Lock()
if len(channel) == 3 {
cond.Broadcast()
cond.Wait()
}
channel <- i
fmt.Println("生产了", i)
cond.L.Unlock()
}
}
func consume(channel <-chan int) {
for i := 0; i < 50; i++ {
cond.L.Lock()
if len(channel) == 0 {
cond.Broadcast()
cond.Wait()
}
num := <-channel
fmt.Println("......消费了", num)
cond.L.Unlock()
}
}
好了 搞定
生产了 15
生产了 16
生产了 17
......消费了 15
......消费了 16
......消费了 17
搞定了