golang学习笔记——面试题 使用 3 个协程顺序打印 cat、dog、fish 各 100 次

文章目录

  • 面试题 使用 3 个协程顺序打印 cat、dog、fish 各 100 次
  • 拓展
    • 第一种方法
    • 第二种方法
  • 参考资料

面试题 使用 3 个协程顺序打印 cat、dog、fish 各 100 次

编程题:3个函数分别打印cat、dog、fish,要求每个函数都要起一个goroutine,按照cat、dog、fish顺序打印在屏幕上100次。

package mainimport ("fmt""sync"
)// 面试题:每个函数起一个goroutine,轮流打印 cat dog fish 各100次
// 3个goroutine, 打印顺序是 cat dog fish cat dog fish ... 依此类推
var wg sync.WaitGroupfunc main() {chCatOk := make(chan struct{}, 1)chDogOk := make(chan struct{}, 1)chFishOk := make(chan struct{}, 1)wg.Add(3) // 有3个协程,所以加3go printAnimal("cat", chCatOk, chDogOk)go printAnimal("dog", chDogOk, chFishOk)go printAnimal("fish", chFishOk, chCatOk)// 先通知cat执行chCatOk <- struct{}{}wg.Wait()fmt.Println("执行结束")
}func printAnimal(word string, ch1 <-chan struct{}, ch2 chan<- struct{}) {count := 0// 退出前标记完成defer wg.Done()for _ = range ch1 {fmt.Println(word)count++ch2 <- struct{}{} // 通知协程2你可以执行了if count == 100 {return}}
}

这个代码只用了一个函数,面试时你可以换成三个名字不一样的函数。

拓展

思考,可否换成无缓冲区的 channel

不可以,会报fatal error: all goroutines are asleep - deadlock!

package mainimport "fmt"func main() {pipline := make(chan string)pipline <- "hello world"fmt.Println(<-pipline)
} 

运行会抛出错误,如下

fatal error: all goroutines are asleep - deadlock!

看起来好像没有什么问题?先往信道中存入数据,再从信道中读取数据。

回顾前面的基础,我们知道使用 make 创建信道的时候,若不传递第二个参数,则你定义的是无缓冲信道,而对于无缓冲信道,在接收者未准备好之前,发送操作是阻塞的.

因此,对于解决此问题有两种方法:

  1. 使接收者代码在发送者之前执行
  2. 使用缓冲信道,而不使用无缓冲信道

第一种方法

若要程序正常执行,需要保证接收者程序在发送数据到信道前就进行阻塞状态,修改代码如下

package mainimport "fmt"func main() {pipline := make(chan string)fmt.Println(<-pipline)pipline <- "hello world"
} 

运行的时候还是报同样的错误。问题出在哪里呢?

原来我们将发送者和接收者写在了同一协程中,虽然保证了接收者代码在发送者之前执行,但是由于前面接收者一直在等待数据 而处于阻塞状态,所以无法执行到后面的发送数据。还是一样造成了死锁。

有了前面的经验,我们将接收者代码写在另一个协程里,并保证在发送者之前执行,就像这样的代码

package mainfunc hello(pipline chan string)  {<-pipline
}func main()  {pipline := make(chan string)go hello(pipline)pipline <- "hello world"
}

运行之后 ,一切正常。

第二种方法

接收者代码必须在发送者代码之前 执行,这是针对无缓冲信道才有的约束。

既然这样,我们改使用有缓冲信道不就 OK 了吗?

package mainimport "fmt"func main() {pipline := make(chan string, 1)pipline <- "hello world"fmt.Println(<-pipline)
} 

运行之后,一切正常。

参考资料

Go 语言中通道死锁经典错误案例详解
解决fatal error: all goroutines are asleep - deadlock!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法训练营Day46(动态规划8之多重背包)

多重背包 关于 多重背包&#xff0c;力扣上没有相关的题目&#xff0c;所以今天的重点就是回顾一波 自己做的背包题目 本题力扣上没有原题&#xff0c;大家可以去卡码网第56题 (opens new window)去练习 简单介绍 有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用&…

【GitHub项目推荐--不错的 Java 开源项目】【转载】

1 基于 Java 的沙盒塔防游戏 Mindustry 是一款用 Java 编写的沙盒塔防游戏。玩家需要建造精密的传送带供应链&#xff0c;提供炮塔弹药&#xff0c;生产建筑材料&#xff0c;保护建筑并抵御敌人。也可以在跨平台多人合作游戏中与朋友一起战斗&#xff0c;或组队进行 PVP 比赛。…

多图合并二维码的制作方法,快速在线生成图片二维码

怎么将多张图合并用二维码展示呢&#xff1f;现在经常会通过扫码的方式来查看图片&#xff0c;选择这种方式不仅可以展现更多地内容&#xff0c;还能够减少图片对个人容量的占用&#xff0c;增加用户的交互性和娱乐性。那么如何使用二维码生成器来快速制作图片二维码呢&#xf…

openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)

文章目录 openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)概述效果笔记编程环境界面控件的设置增加文件拖拽的类RSA证书和key是否匹配的实现在程序中加入环境变量备注备注END openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具) 概述 在学习openssl官方的…

Python 变量?对象?引用?赋值?一个例子解释清楚

哈喽大家好&#xff0c;我是咸鱼。 前天有个小伙伴找到我&#xff0c;给了我一段 python 代码&#xff1a; a [1, 2] a[1] a print(a[1])然后问我为什么结果是 [1, [...]]&#xff0c;我一看这个问题有意思&#xff0c;我说三言两语解释不清楚&#xff0c;我写篇文章到时候…

和硕拿下AI Pin代工大单公司 | 百能云芯

和硕公司近日成功中标AI Pin代工大单&#xff0c;AI Pin被认为是继iPhone之后的下一个划时代产品&#xff0c;吸引了全球科技圈的广泛关注。和硕公司对此表示&#xff0c;他们不会只专注于单一客户&#xff0c;而是期望在下半年有更多新品上市&#xff0c;为公司带来丰硕的业绩…

自定义注解使用案例,

后续会加上详细注释&#xff0c;或者出一个贴图详细的2.0版本&#xff0c;大家不要错过&#xff01;我会详细教大家如何使用自定义注解开发&#xff01;让你的代码瞬间高大上起来 Data public class ReportDateDTO {/*** 年*/ApiModelProperty(value "年", notes &…

C++ -- 入门(引用)

1.引用 1.1引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称&q…

CC工具箱使用指南:【平差工具】

一、简介 平差是一个摘自英文单词“adiustment”的中文翻译&#xff0c;它最初源于土地测量工程&#xff0c;并在后来广泛应用于各个测量领域在传统的测量中&#xff0c;由于各种误差的存在&#xff0c;例如仪器、人为、大地形态等因素&#xff0c;所得到的测量结果是不完全准…

MySQL基础(一)

学习数据库的目的&#xff1a; 实现数据持久化到本地。使用完整的管理系统统一管理&#xff0c;可以实现结构化查询&#xff0c;方便管理。 一、数据库概述 数据库&#xff08;DataBase&#xff09; 为了方便数据的存储和管理&#xff0c;它将数据按照特定的 规则存储在磁盘…

项目解决方案: 视频融合(实时监控视频和三维建模进行融合)设计方案

目 录 一、需求描述 1、视频接入和控制要求 2、视频播放需求 3、提供其他应用的调用 二、方案设计 &#xff08;一&#xff09;系统设计图 &#xff08;二&#xff09;产品实现方案 三、产品和功能描述 &#xff08;一&#xff09;总体描述 &#xf…

Java 数据结构集合

文章目录 Java 数据结构1. 基本数据结构1.1 数组 (Array)1.2 链表 (Linked List)1.3 栈 (Stack)1.4 队列 (Queue)双向队列优先级队列 2. 树形数据结构2.1 二叉树 (Binary Tree)2.2 堆 (Heap) 3. 散列数据结构3.1 哈希表 (Hash Map)3.2 LinkedHashMap3.3 TreeMapConcurrentHashM…

【C++练级之路】【Lv.7】【STL】vector类的模拟实现

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、成员变量二、默认成员函数2.1 constructor2.2 destructor2.3 copy constructor2.4 operator 三、迭代器…

Java毕业设计-基于jsp+servlet的学生推荐平台管理系统-第81期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于jspservlet的学生推荐平台管理系统&#xff1a;前端 jsp、jquery&#xff0c;后端 servlet、jdbc&#xff0c;集成用户端和管理后台&#xff0c;用户端浏览书籍课程&…

C++ 字符串库 std::basic_string

std::basic_string C 字符串库 std::basic_string 在标头 定义 template<class CharT,class Traits std::char_traits<CharT>,class Allocator std::allocator<CharT> > class basic_string;(1) namespace pmr { template<class CharT,class Traits …

【运维】如何恢复默认的~/.bashrc

可以通过使用系统默认的.bashrc文件来恢复它。以下是一些步骤&#xff0c;具体操作可能因系统而异&#xff1a; 使用默认.bashrc文件&#xff1a; 大多数Linux系统都会提供一个默认的.bashrc文件。您可以复制系统默认的文件到您的主目录。 cp /etc/skel/.bashrc ~/上述命令会将…

MySQL之数据库DML

文章目录 数据操作DML插入修改删除 数据操作DML 这里的数据操作就是增删改的更新操作&#xff0c;不包括查询 插入 insert into 表 (列名1,列名2,列名3...) values (值1,值2,值3...); //向表中插入对应列 insert into 表 values (值1,值2,值3...); //向表中插入所有列第…

python基础——进程

multiprocessing模块 与进程相关的模块 使用main进程创建子进程 from multiprocessing import Process import os def func():print("这是一个func函数&#xff0c;进程号为&#xff1a;{}&#xff0c;父进程号为&#xff1a;{}".format(os.getpid(),os.getppid(…

Web06--JavaScript基础02

1、JS流程控制语句 JS与Java一样&#xff0c;也有三个流程控制语句&#xff1a; 顺序结构 选择结构 循环结构 1.1 选择结构 1.1.1 if结构 <script type"text/javascript">if (条件表达式) {代码块;} else if(条件表达式){代码块;} else {代码块;} </scr…

kafka入门(九):kafka分区分配策略

kafka分区分配策略 参数&#xff1a; Kafka提供了消费者客户端参数partition.assignment.strategy来设置消费者与订阅主题之间的分区分配策略。 默认情况下&#xff0c;此参数的值为 org.apache.kafka.clients.consumer.RangeAssignor&#xff0c;即采用RangeAssignor分配策略。…