让go语言健壮并发(二)

        上一章我们我们已经讲解了go语言的消费者,这一章我们讲解生产者,这一章的内容涉及到通过channel进行信号同步。信号同步会遇到时间迟滞,子协程存在竞争,会导致偶然的死锁,如何解决这个同步问题,让程序健壮地并发是我们这一章的重点内容。

直接上代码。

// gochan_1.go
package main

import (
	"fmt"
)

func producer(ch chan int) {
	for i := 0; i < 5; i++ {
		ch <- i
	}
	close(ch)
}
func main() {
	ch := make(chan int)
	go producer(ch)
	for num := range ch {
		fmt.Println("num=", num)
	}
	fmt.Println("game over!")
}

我们要让生产者无限制生产数据,直到接到信号停止生产。

这就需要增加一个channel进行信号同步,是否能达到目的呢,我们先看看代码。

// goifok.go
package main

import (
	"fmt"
	"time"
)

func main() {
	quit := make(chan bool)
	go func() {
		time.Sleep(time.Second * 3)
		quit <- true
	}()
	if q, ok := <-quit; ok {
		fmt.Println("ok", q)
	} else {
		fmt.Println("not ok")
	}
	fmt.Println("Hello World!")
}

我们增加了一个叫quit的channel进行信号同步,这个通道需要传入一个bool值,不管这个值是true or false,只要有值就能达到目的。增加这个信号就能达到目的了吗?我们看看运行结果。

出现了死锁。这是什么原因呢?这是由于要先生产数据,只有满足条件后才会有退出信号通过通道quit传进来,但是由于没有值传进来,信号就会发生堵塞。这就是死锁的原因。对于有两个以上信号的我们要用select来进行条件控制。

// gochan_1.go
package main

import (
	"fmt"
	"time"
)

func producer(ch chan int, quit chan bool) {
	i := 1
	for {
		select {
		case <-quit:
			close(ch)
			fmt.Println("quit")
			return
		default:
			ch <- i
			i++
		}
	}

}
func main() {
	ch := make(chan int)
	quit := make(chan bool)
	go producer(ch, quit)
	for num := range ch {
		if num >= 5 {
			quit <- true
			close(quit)

		}
		time.Sleep(time.Second)
		fmt.Println("num=", num)
	}
	fmt.Println("game over!")
}

 从上面的运行结果看,没有发生死锁,是不是可以结束了呢?多试几次仍然会发生死锁。多运行几次 go run -race gochan_1.go会发生堵塞,程序不能结束。

什么原因导致这个偶发的错误呢?

我们需要健壮的运行并发程序,怎么避免这种情况呢?下一节继续讲解这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值