当前位置:首页 > 科技  > 软件

聊聊协程和管道—管道

来源: 责编: 时间:2023-08-09 23:03:10 220观看
导读管道简介【1】管道(channel)特质介绍:(1)管道本质就是一个数据结构-队列(2)数据是先进先出(3)自身线程安全,多协程访问时,不需要加锁,channel本身就是线程安全的(4)管道有类型的,一个string的管道只能存放string类型数据管道入门案例

管道简介

【1】管道(channel)特质介绍:

(1)管道本质就是一个数据结构-队列H6R28资讯网——每日最新资讯28at.com

(2)数据是先进先出H6R28资讯网——每日最新资讯28at.com

(3)自身线程安全,多协程访问时,不需要加锁,channel本身就是线程安全的H6R28资讯网——每日最新资讯28at.com

(4)管道有类型的,一个string的管道只能存放string类型数据H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

管道入门案例

【1】管道的定义:

var 变量名 chan 数据类型H6R28资讯网——每日最新资讯28at.com

PS1:chan管道关键字H6R28资讯网——每日最新资讯28at.com

PS2:数据类型指的是管道的类型,里面放入数据的类型,管道是有类型的,int类型的管道只能写入整数intH6R28资讯网——每日最新资讯28at.com

PS3:管道是引用类型,必须初始化才能写入数据,即make后才能使用H6R28资讯网——每日最新资讯28at.com

【2】案例:

func main()  {	//定义管道 、 声明管道 ---> 定义一个int类型的管道	var intChan chan int	//通过make初始化:管道可以存放3个int类型的数据	intChan = make(chan int, 3)	//证明管道是引用类型:	fmt.Printf("intChan的值: %v /n",intChan)	//向管道存放数据:	intChan <- -10	num := 20	intChan <- num	intChan <- 40	//注意:不能存放大于容量的数据:	// intChan <- -80	//输出管道的长度:	fmt.Printf("管道的实际长度:%v,管道的容量是:%v /n",len(intChan),cap(intChan))	//在管道中读取数据:	num1 := <-intChan	num2 := <-intChan	num3 := <-intChan	fmt.Println(num1)	fmt.Println(num2)	fmt.Println(num3)	//注意:在没有使用协程的情况下,如果管道的数据已经全部取出,那么再取就会报错:	// num4 := <-intChan	// fmt.Println(num4)	fmt.Printf("管道的实际长度:%v,管道的容量是:%v /n",len(intChan),cap(intChan))}

管道的关闭

【1】管道的关闭:

使用内置函数close可以关闭管道,当管道关闭后,就不能再向管道写数据了,但是仍然可以从该管道读取数据。H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

【2】案例:

func main()  {	var intChan chan int	intChan = make(chan int, 3)	intChan <- 10	intChan <- 20	//关闭管道:	close(intChan)	//再次写入数据:--->报错	// intChan <- 30	//当管道关闭后,读取数据是可以的:	num := <- intChan	fmt.Println(num)}

管道的遍历

【1】管道的遍历:

管道支持for-range的方式进行遍历,请注意两个细节H6R28资讯网——每日最新资讯28at.com

1)在遍历时,如果管道没有关闭,则会出现deadlock的错误H6R28资讯网——每日最新资讯28at.com

2)在遍历时,如果管道已经关闭,则会正常遍历数据,遍历完后,就会退出遍历。H6R28资讯网——每日最新资讯28at.com

【2】案例:

func main()  {	var intChan chan int	intChan = make(chan int, 100)	for i := 0; i < 100; i++ {		intChan <- i	}	//在遍历前,如果没有关闭管道,就会出现deadlock的错误	//所以我们在遍历前要进行管道的关闭	// for v := range intChan {	// 	fmt.Println("value = ",v)	// }	close(intChan)	//遍历:for-range	for v := range intChan {		fmt.Println("value = ",v)	}}

协程和管道协同工作案例

【1】案例需求:

请完成协程和管道协同工作的案例,具体要求:H6R28资讯网——每日最新资讯28at.com

1) 开启一个writeData协程,向管道中写入50个整数.H6R28资讯网——每日最新资讯28at.com

2) 开启一个readData协程,从管道中读取writeData写入的数据。H6R28资讯网——每日最新资讯28at.com

3) 注意: writeData和readDate操作的是同一个管道H6R28资讯网——每日最新资讯28at.com

4) 主线程需要等待writeData和readDate协程都完成工作才能退出H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

【2】原理图:

H6R28资讯网——每日最新资讯28at.com

package mainimport (	"fmt"	"time"	"sync")var wg sync.WaitGroup//写:func writeData(intChan chan int)  {	defer wg.Done()	for i := 1; i <= 50; i++ {		intChan <- i		fmt.Println("写入的数据为:",i)		time.Sleep(time.Second)	}		close(intChan)}//读:func readData(intChan chan int) {	defer wg.Done()	for v := range intChan {		fmt.Println("读取的数据为:",v)		time.Sleep(time.Second)	}}func main()  {	//主线程	//写协程和读协程共同操作同一个管道-》定义管道:	intChan := make(chan int, 50)	wg.Add(2)	//开启读和写的协程:	go writeData(intChan)	go readData(intChan)	//主线程一直在阻塞,什么时候wg减为0了,就停止	wg.Wait()	fmt.Println("读写数据完成...")}

运行结果:H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

声明只读只写管道

【1】管道可以声明为只读或者只写性质

【2】代码:

package mainimport (	"fmt")func main()  {	//默认情况下,管道是双向的--》可读可写:	//声明为只写:	// 管道具备<- 只写性质	var intChan chan<- int	intChan = make(chan int, 3)	intChan <- 10	// 报错	// num := <- intChan	fmt.Println("intChan:",intChan)	//声明为只读:	// 管道具备<- 只读性质 	var intChan2 <-chan int	if intChan2 != nil {		num1 := <- intChan2		fmt.Println("num1:",num1)	}	// 报错	// intChan2 <- 30}

管道的阻塞

【1】当管道只写入数据,没有读取,就会出现阻塞:

package mainimport (	"fmt"	"sync")var wg sync.WaitGroupfunc writeData(intChan chan int)  {	defer wg.Done()	for i := 1; i < 10; i++ {		intChan <- i		fmt.Println("写入的数据:",i)	}	close(intChan)}func readData(intChan chan int)  {	defer wg.Done()	for v := range intChan {		fmt.Println("读取的数据为:",v)	}}func main()  {	intChan := make(chan int, 10)	wg.Add(2)	go writeData(intChan)	// go readData(intChan)	wg.Wait()}

运行结果H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

【2】写的快,读的慢(管道读写频率不一致),不会出现阻塞问题:

package mainimport (	"fmt"	"sync"	"time")var wg sync.WaitGroupfunc writeData(intChan chan int)  {	defer wg.Done()	for i := 1; i < 10; i++ {		intChan <- i		fmt.Println("写入的数据:",i)	}	close(intChan)}func readData(intChan chan int)  {	defer wg.Done()	for v := range intChan {		fmt.Println("读取的数据为:",v)		time.Sleep(time.Second)	}}func main()  {	intChan := make(chan int, 10)	wg.Add(2)	go writeData(intChan)	go readData(intChan)	wg.Wait()}

select功能

【1】select功能:解决多个管道的选择问题,也可以叫做多路复用,可以从多个管道中随机公平地选择一个来执行

PS:case后面必须进行的是io操作,不能是等值,随机去选择一个io操作H6R28资讯网——每日最新资讯28at.com

PS:default防止select被阻塞住,加入defaultH6R28资讯网——每日最新资讯28at.com

【2】代码:

package mainimport (	"fmt"	"time")func main()  {	intChan := make(chan int, 1)	go func ()  {		time.Sleep(time.Second * 15)		intChan <- 15	}()	stringChan := make(chan string, 1)	go func ()  {		time.Sleep(time.Second * 12)		stringChan <- "hellocyz"	}()	//本身取数据就是阻塞的	// fmt.Println(<-intChan)	select {		case v := <-intChan : fmt.Println("intChan:",v)		case v := <-stringChan : fmt.Println("stringChan:",v)		default: fmt.Println("防止select被阻塞")	}}

defer+recover机制处理错误

【1】问题原因:多个协程工作,其中一个协程出现panic,导致程序崩溃

【2】解决办法:利用defer+recover捕获panic进行处理,即使协程出现问题,主线程仍然不受影响可以继续执行。

【3】案例:

package mainimport (	"fmt"	"time")//输出数字:func printNum()  {	for i := 1; i <= 10; i++ {		fmt.Println(i)		}}//做除法操作:func divide()  {	defer func ()  {		err := recover()		if err != nil {			fmt.Println("devide()出现错误:",err)		}	}()	num1 := 10	num2 := 0	result := num1 / num2	fmt.Println(result)}func main()  {	//启动两个协程:	go printNum()	go divide()	time.Sleep(time.Second * 5)}

结果:H6R28资讯网——每日最新资讯28at.com

H6R28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-5170-0.html聊聊协程和管道—管道

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 如何使用Kafka构建事件驱动的架构​

下一篇: 空间智能化为产业转型带来新动能,华为开放能力与合作伙伴共赢时代

标签:
  • 热门焦点
  • Redmi Buds 4开箱简评:才199还有降噪 可以无脑入

    Redmi Buds 4开箱简评:才199还有降噪 可以无脑入

    在上个月举办的Redmi Note11T Pro系列新机发布会上,除了两款手机新品之外,Redmi还带来了两款TWS真无线蓝牙耳机产品,Redmi Buds 4和Redmi Buds 4 Pro,此前我们在Redmi Note11T
  • 一篇聊聊Go错误封装机制

    一篇聊聊Go错误封装机制

    %w 是用于错误包装(Error Wrapping)的格式化动词。它是用于 fmt.Errorf 和 fmt.Sprintf 函数中的一个特殊格式化动词,用于将一个错误(或其他可打印的值)包装在一个新的错误中。使
  • .NET 程序的 GDI 句柄泄露的再反思

    .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    来源 | 烈酒商业观察编 | 肖海林今年以来,威士忌市场开始出现了降温迹象,越来越多不断暴涨的网红威士忌也开始悄然回归市场理性。近日,LVMH集团旗下苏格兰威士忌品牌雅柏(Ardbeg
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    来源:极点商业作者:杨铭在淘宝购买珠宝玉石后,因为保证金不够赔付,店铺关闭,退货退款难、维权无门的比比皆是。&ldquo;提供相关产品鉴定证书,支持全国复检,可以30天无理由退换货。&
  • iQOO Neo8 Pro评测:旗舰双芯加持 最强性能游戏旗舰

    iQOO Neo8 Pro评测:旗舰双芯加持 最强性能游戏旗舰

    【Techweb评测】去年10月,iQOO推出了一款Neo7手机,该机搭载了联发科天玑9000+,配备独显芯片Pro+,带来了同价位段最佳的游戏体验,一经上市便受到了诸多用
  • 与兆芯合作  联想推出全新旗舰版笔记本电脑开天N7系列

    与兆芯合作 联想推出全新旗舰版笔记本电脑开天N7系列

    联想与兆芯合作推出全新联想旗舰版笔记本电脑开天 N7系列。这个系列采用兆芯KX-6640MA处理器平台,KX-6640MA 处理器是采用了陆家嘴架构,16nm 工艺,4 核 4 线
  • 北京:科技教育体验基地开始登记

    北京:科技教育体验基地开始登记

      北京“科技馆之城”科技教育体验基地登记和认证工作日前启动。首批北京科技教育体验基地拟于2023年全国科普日期间挂牌,后续还将开展常态化登记。  北京科技教育体验基
Top