关于channel的一些问题

来源:13-8 双向和单向的channel

JxinBain

2021-05-31

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func comsumer(queue chan int) {
	defer wg.Done()
	for {
		data, ok := <-queue
		if !ok {
			break
		}
		fmt.Println(data, ok)
		time.Sleep(time.Second)
		/*
			把添加数据到channel的语句挪到for循环之内,程序正常运行
		*/
		//queue <- 20
		//fmt.Println("添加数据成功")
	}
	fmt.Println("循环结束")
	/*
		把添加数据到channel的语句挪到for循环之外,则会报错
	*/
	queue <- 20
	fmt.Println("添加数据成功")
}

func main() {
	/*
		channel 类型分类的两个维度
		有缓冲的还是无缓冲的
		单项的还是双向的
	*/
	// 定义一个channel
	var msgs chan int
	msgs = make(chan int) // 第一种初始化方式:无缓冲 先启动消费者 再放数据 就不会panic
	wg.Add(1)
	go comsumer(msgs)
	msgs <- 1
	fmt.Println("等待返回值")
	// 这里从管道取值是会阻塞 如果注释掉这行代码 那么管道会直接关闭 导致 comsumer方法里面给管道里添加值的语句报错
	data := <-msgs
	fmt.Println(data)
	close(msgs)
	//fmt.Println("channel已关闭")
	wg.Wait()
}

老师你好 我想请问一下 关于我comsumer方法里面 我把添加数据到channel的语句(queue <- 20)挪到for循环体外面的时候,程序会报错 以下是错误信息

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
        D:/LessonProject/Go-Python微服务/GoProject/GoLang/c13/channel_type/main.go:48 +0x128

goroutine 6 [chan receive]:
main.comsumer(0xc00004a060)
        D:/LessonProject/Go-Python微服务/GoProject/GoLang/c13/channel_type/main.go:14 +0x137
created by main.main
        D:/LessonProject/Go-Python微服务/GoProject/GoLang/c13/channel_type/main.go:44 +0x8a

但是如果我把 queue <- 20 放到循环体内的时候 程序则不会报错 程序正常运行 这是为什么呢?

写回答

1回答

bobby

2021-06-01

首先这个问题非常棒,也是非常好的案例,这是一个典型的go的无缓冲channel的细节问题,实际开发过程中很容易面临,而且面试过程中也很容易遇到,其实一句话总结就是:

无缓冲channel容易踩坑, 先说一句结论:无缓冲的channel发送的时候需要有地方应开始等着接收了。反过来也是一样的,你上面把发送放到外面,https://zhuanlan.zhihu.com/p/101063277 你可以先看看这篇好好了解一下无缓冲channel 

0
2
bobby
回复
JxinBain
好的。
2021-06-04
共2条回复

Go+Python打造电商系统 自研微服务框架 抓紧高薪机遇

快速转型Go工程师,成为具备双语言后端能力的开发者

508 学习 · 530 问题

查看课程