无缓冲通道和死锁

无缓冲通道在发送和接收数据时都会阻塞

好处:goroutine 可以在没有明确的锁或竞态变量的情况下进行同步。

package main

import(
	"fmt"
	"math/rand"
	"time"
)

func getNumber(){
	var i int = 1
	fmt.Println(i)
	i++
	
}

func call(){
	go getNumber()
	go getNumber()
}
func main() {
    call()
	sleep := rand.Int63n(100)
	time.Sleep(time.Duration(sleep) * time.Millisecond)
}
输出1           1

package main

import(
	"fmt"
	"math/rand"
	"sync"
	"time"
)

const(
	numberGoroutines = 4
	taskLoad = 10
)

var wg sync.WaitGroup

func init(){
	rand.Seed(time.Now().Unix())
}

func main(){
	tasks := make(chan string,taskLoad)
	wg.Add(numberGoroutines)
	for gr := 1; gr <= numberGoroutines; gr++{
		go worker(tasks,gr)
	}
	for post :=1;post <= taskLoad;post++ {
		tasks <- fmt.Sprintf("Task : %d",post)
	}
	close(tasks)
	wg.Wait()
}

func worker(tasks chan string, worker int) {
	 // 通知函数已经返回
	defer wg.Done()

	for {
		 // 等待分配工作
		 //每个 goroutine 都会在此阻塞,等待从通道里接收新的工作。一旦接收到返回,就会检查 ok 标志,看通道是否已经清空而且关闭。
		task, ok := <-tasks

		if !ok {
			 // 这意味着通道已经空了,并且已被关闭
			fmt.Printf("Worker: %d : Shutting Down\n", worker)
			return
		}

		 // 显示我们开始工作了
		fmt.Printf("Worker: %d : Started %s\n", worker, task)

		 // 随机等一段时间来模拟工作
		sleep := rand.Int63n(100)
		time.Sleep(time.Duration(sleep) * time.Millisecond)

		 // 显示我们完成了工作
		fmt.Printf("Worker: %d : Completed %s\n", worker, task)
	}
}
输出1          2

坏处:稍不注意就写个死锁,如下

单线程操作无缓冲通道死锁

package main

import "fmt"

func main() {
	ch := make(chan int)
	ch <- 1  //造成死锁
	out := <-ch
	fmt.Println(out)
	close(ch)
}
粗略看一下上边代码的流程是创建channel-----》存放数据-----》取出数据----------》打印输出---------》关闭channel,流程貌似没错。造成死锁的原因在于 无缓冲的信道在取消息和存消息的时候都会挂起当前的goroutine,而当前只有1个main的线程(也是一个goroutine),所以在进行存放数据的ch <- 1这一行,就会产生锁,导致后边代码无法执行。而整个程序无其它线程来让这个锁释放,自然就形成了一个死锁。

单通道多线程死锁

package main

import "fmt"

var ch chan int = make(chan int)

func main() {
	ch := make(chan int)
	ch <- 1
	var a int
	go func(){
	   a = <-ch
	}()
	fmt.Println(a)
}


多通道多线程存取不匹配死锁

package main

import "fmt"

var ch1 chan int = make(chan int)
var ch2 chan int = make(chan int)

func say(ch chan int) {
    fmt.Println(ch)
    ch1 <- <- ch2 // ch1 等待 ch2流出的数据
}

func main() {
    go say(ch2)  
    <- ch1  // 堵塞主线
}

上边的代码有2个goroutine、2个通道,造成死锁的原因为主线等ch1中的数据流出,ch1等ch2的数据流出,但是ch2等待数据流入,两个goroutine都在等,也就是死锁。

package main

import "fmt"

func main() {
	c, quit := make(chan int), make(chan int)
	
	go func() {
	   c <- 1  // c通道的数据没有被其他goroutine读取走,堵塞当前goroutine
	   quit <- 0 // quit始终没有办法写入数据
	}()
	
	<- quit
}


试试看如下代码的运行结果

package main

import "fmt"

func main() {
    ch := make(chan int) 
	go func(){
		ch <- 1
	}()
	fmt.Println(len(ch)) 
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的梧桐述

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值