当前位置: 首页 > news >正文

Golang协程常见面试题

协程面试题

  • 交替打印奇数和偶数
  • N个协程打印1到maxVal
  • 交替打印字符和数字
  • 交替打印字符串
  • 三个协程打印ABC
  • Channel练习

交替打印奇数和偶数

下面让我们一起来看看golang当中常见的算法面试题
使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出.
方法一:使用无缓冲的channel进行协程间通信

package mainimport ("fmt""sync"
)// PrintOddAndEven1 /*
func PrintOddAndEven1() {//方法一,使用无缓冲的channel进行通信var wg = new(sync.WaitGroup) //注意这里需要是指针go语言当中都是值传递wg.Add(2)ch := make(chan struct{}) //无缓冲channeldefer close(ch)maxVal := 100go func() {defer wg.Done()for i := 1; i <= maxVal; i++ {ch <- struct{}{}if i%2 == 1 { //奇数fmt.Printf("the odd is %d\n", i)}}}()go func() {defer wg.Done()for i := 1; i <= maxVal; i++ {<-ch          //从管道当中读取一个数据if i%2 == 0 { //偶数fmt.Printf("the even is %d\n", i)}}}()wg.Wait()}
func main() {PrintOddAndEven1()fmt.Println("over")
}

下面博主来解释一下这个的原理 首先因为变量ch是一个无缓冲的channel, 所以只有读写同时就绪时才不会阻塞。所以两个goroutine会同时进入各自的 if 语句(此时 i 是相同的),但是此时只能有一个 if 是成立的,不管goroutine快,都会由于读channel或写channel导致阻塞,因此程序会交替打印1-100且有顺序。

方法二:使用有缓冲的channel

func PrintOddAndEven2() {var wg = new(sync.WaitGroup) //注意这里需要是指针go语言当中都是值传递wg.Add(2)oddChan := make(chan struct{}, 1)eveChan := make(chan struct{}, 1)defer close(oddChan)defer close(eveChan)oddChan <- struct{}{}maxVal := 20go func() { //奇数协程defer wg.Done()for i := 1; i <= maxVal; i += 2 {<-oddChanfmt.Printf("the odd print %d\n", i)eveChan <- struct{}{} //通知偶数协程}}()go func() {//偶数协程defer wg.Done()for i := 2; i <= maxVal; i += 2 {<-eveChanfmt.Printf("the even print %d\n", i)oddChan <- struct{}{} //通知奇数协程可以打印了}}()wg.Wait()}func main() {PrintOddAndEven2()fmt.Println("over")
}

第二个方法使用这个有缓冲的channel。有缓冲的channel当容量没有达到上限时写入不会阻塞在这里奇数协程的channel容量为1我们提前给他写入了一个数据因此当偶数和奇数协程都开始读取数据时,首先读取到数据的是奇数协程,奇数协程打印完之后在通知偶数协程打印,偶数协程打印完成之后在通知奇数协程重复下去就实现了交替打印的效果。

N个协程打印1到maxVal

题目描述非常的简单就是N个协程交替打印1到maxVal。比如N=3,maxVal是这个100效果应该是第一个协程打印1,第二个协程打印2,第三个协程打印3,第一个协程打印4这样的效果。
这道题看起来非常的复杂,博主第一次看到这个题的时候也感觉很复杂但是仔细想一下其实并没有那么复杂和上面两题的解题思路是一样的。下面我们看看这个代码如何实现

package mainimport ("fmt""sync"
)func main() {maxVal := 10res := 0                        //用于打印数字N := 3                          //协程的数量exitChan := make(chan struct{}) //用于退出chanArr := make([]chan struct{}, N)for i := 0; i < N; i++ {//使用无缓冲的channelchanArr[i] = make(chan struct{}, 1)}num := 0 //记录轮到那个协程开始打印了chanArr[0] <- struct{}{}for i := 0; i < N; i++ {go func(i int) {for {<-chanArr[i]if res >= maxVal {exitChan <- struct{}{}break}fmt.Printf("第%d个协程打印%d\n", i, res)if num == N-1 {//已经循环一轮了轮到第0个协程打印数据了num = 0} else {num++}res++chanArr[num] <- struct{}{} //第num个协程可以打印数据了}}(i)}<-exitChanfor i := 0; i < N; i++ {close(chanArr[i]) //将管道全部关闭否则会有协程泄漏}}

其实也非常的简单也是利用channel来进行这个协程之间的通信,由于是N个协程之间进行通信所以了我们定义一个channel的切片首先往第一个channel当中写入一个数据其他管道没有写入数据那么最先打印的一定是这个第一个协程然后我们在利用一个计数器通知其他协程打印。最后需要注意的是主协程退出时需要将管道全部关闭否则其他协程一致阻塞在那里就会引起协程泄漏,就只能等到gc的时候才能回收。

交替打印字符和数字

问题描述: 使用两个 goroutine 交替打印序列,一个 goroutinue 打印数字, 另外一个goroutine打印字母, 最终效果如下 12AB34CD56EF78GH910IJ 。
如果铁子们上面两题会了那么这道题就是有手就行的那种和第一道题没有啥区别

func main() {numChan := make(chan struct{}, 1)chChan := make(chan struct{}, 1)defer close(numChan)defer close(chChan)var wg sync.WaitGroupwg.Add(2)numChan <- struct{}{}go func() {defer wg.Done()for num := 1; num <= 26; num++ {<-numChanfmt.Printf("%d", num)chChan <- struct{}{}}}()go func() {defer wg.Done()for ch := 'A'; ch <= 'Z'; ch++ {<-chChanfmt.Printf("%s", string(ch))numChan <- struct{}{}}}()wg.Wait()}

同样的也是利用这个channe进行通信,利用有缓冲的channel进行通信。当然也能使用这个无缓冲的channel进行通信

func main() {numChan := make(chan struct{})defer close(numChan)var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()for num := 1; num <= 26; num++ {numChan <- struct{}{}fmt.Printf("%d", num)}}()go func() {defer wg.Done()for ch := 'A'; ch <= 'Z'; ch++ {<-numChanfmt.Printf("%s", string(ch))}}()wg.Wait()

交替打印字符串

题目描述,给定一个字符串使用两个协程交替打印它。
如果老铁们上面的拿到题都会了这道题不就是和第一道题是这个一模一样的吗?废话不多说直接上代码
方法一使用无缓冲的channel


func main() {chChan := make(chan struct{})defer close(chChan)var wg = new(sync.WaitGroup)wg.Add(2)str := "hello world"N := len(str)go func() {defer wg.Done()for i := 0; i < N; i++ {chChan <- struct{}{}if i%2 == 0 {fmt.Println(string(str[i]))}}}()go func() {defer wg.Done()for i := 0; i < N; i++ {<-chChanif i%2 == 1 {fmt.Println(string(str[i]))}}}()wg.Wait()}

当然也可以使用有缓冲的channel在这里铁子们可以自行编写上面写的太多了。

三个协程打印ABC

题目描述使用三个协程分别打印A,B,C打印这个100次。
本题的难度和上面那几个题完全是一个货色,我们可以使用三个有缓冲的channel就可以达到目的了。具体细节请看代码

package mainimport ("fmt""sync"
)func main() {Achan := make(chan struct{}, 1)Bchan := make(chan struct{}, 1)Cchan := make(chan struct{}, 1)defer close(Achan)defer close(Bchan)defer close(Cchan)Achan <- struct{}{}counter := 0maxVal := 10exitChan := make(chan struct{}) //用于退出go func() {for {<-Achanif counter >= maxVal {exitChan <- struct{}{}break}fmt.Printf("%s ", "A")counter++Bchan <- struct{}{}}}()go func() {for {<-Bchanif counter >= maxVal {exitChan <- struct{}{}break}fmt.Printf("%s ", "B")counter++Cchan <- struct{}{}}}()go func() {for {<-Cchanif counter >= maxVal {exitChan <- struct{}{}break}fmt.Printf("%s ", "C")counter++Achan <- struct{}{}}}()<-exitChan
}

在这里需要注意的点是我们需要close掉这个管道当达到临界值时,主协程退出但是defer方法会执行这个时候管道一关闭所有协程都会收到退出信号,另外两个阻塞在那里的协程就会退出这样就没有这个协程泄漏了。

##并发将多个文件合并到一个文件当中
MergeFile 把多个文件合成一个文件,并发实现子协程优雅退出。采用并发的方式
本题的解题思路同样的也非常的简单我们可以定义一个管道并发的读取文件写入到管道当中然后再并发的写入到文件当中。非常的简单

package mainimport ("bufio""fmt""io""os""strconv""sync"
)// MergeFile 把多个文件合成一个文件,并发实现子协程优雅退出var fileChan = make(chan string, 10000)
var writeFish = make(chan struct{})
var wg sync.WaitGroupfunc readFile(fileName string) {fin, err := os.Open(fileName)if err != nil {fmt.Println(err.Error())return}defer fin.Close()defer wg.Done()reader := bufio.NewReader(fin)for {line, err := reader.ReadString('\n') //注意已经包含换行符了if err != nil {if err == io.EOF {if len(line) > 0 {line += "\n"fileChan <- line}break} else {fmt.Println(err)break}} else if line == "\r\n" {fmt.Println("进来")continue} else {fileChan <- line}}}
func writeFile(fileName string) {fout, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)if err != nil {fmt.Println(err)return}defer fout.Close()defer func() {close(writeFish)}()writer := bufio.NewWriter(fout)//LOOP://	for {//		select {//		case <-readFish://			close(fileChan)//注意需要关闭因为已经没有人往里面写了//			for line:=range fileChan{//				writer.WriteString(line) //读取时候已经包含换行符了//			}//			break LOOP//		case line := <-fileChan://			writer.WriteString(line) //读取时候已经包含换行符了//		}////	}for {if line, ok := <-fileChan; ok {if line != "\r\n" {writer.WriteString(line)}} else {break}}writer.Flush() //刷新}func main() {wg.Add(3)for i := 1; i <= 3; i++ {fileName := "Dir/" + strconv.Itoa(i)go readFile(fileName)}go writeFile("Dir/merge")wg.Wait()close(fileChan)<-writeFish}

Channel练习

启动一个协程生成100个数发送到ch1管道当中,再启动一个协程从ch1当中取值然后计算平方将其放入ch2管道当中主协程打印

package mainimport ("fmt""sync"
)var wg sync.WaitGroupfunc f1(ch1 chan int) {defer wg.Done()for i := 0; i < 50; i++ {ch1 <- i}close(ch1)
}
func f2(ch2 chan int, ch1 chan int) {defer wg.Done()defer close(ch2)for x := range ch1 {ch2 <- x * x}
}
func main() {wg.Add(2)a := make(chan int, 50)b := make(chan int, 50)go f1(a)go f2(b, a)wg.Wait()for x := range b {fmt.Println(x)}}

相关文章:

Golang协程常见面试题

协程面试题交替打印奇数和偶数N个协程打印1到maxVal交替打印字符和数字交替打印字符串三个协程打印ABCChannel练习交替打印奇数和偶数 下面让我们一起来看看golang当中常见的算法面试题 使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出. 方法一&…...

种群多样性:智能优化算法求解基准测试函数F1-F23种群动态变化图(视频)

智能优化算法求解基准测试函数F1种群动态变化图智能优化算法求解基准测试函数F2种群动态变化图智能优化算法求解基准测试函数F3种群动态变化图智能优化算法求解基准测试函数F4种群动态变化图智能优化算法求解基准测试函数F5种群动态变化图智能优化算法求解基准测试函数F6种群动…...

Qt 中的XML

XML的基本介绍&#xff1a; 在前端开发中&#xff1a;HTML是用来显示数据&#xff0c;而XML是用来传输和存储数据的 XML 指可扩展标记语言&#xff08;EXtensible Markup Language&#xff09;XML 是一种标记语言&#xff0c;很类似 HTMLXML 的设计宗旨是传输数据&#xff0c;而…...

网络应用之URL

URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符&#xff0c;通俗理解就是网络资源地址&#xff0c;也就是我们常说的网址。2. URL的组成URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html…...

【Linux】重定向原理dup2缓冲区

文章目录重定向原理输出重定向关于FILE解释输出重定向原理追加重定向输入重定向dup2缓冲区语言级别的缓冲区内核缓冲区重定向原理 重定向的本质就是修改文件描述符下标对应的struct file*的内容 输出重定向 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文…...

ROG配置ubuntu20.04.5双系统要点

win11ubuntu20.04.5 1. BIOS设置 开机长按F2进入bios设置&#xff0c;修改advanced参数&#xff1a; boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled&#xff08;其他电脑是修改硬盘的SATA和ACHI模式&#xff09;。但是改了之后windo…...

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办&#xff1f;最近有用户使用的机械革命旷世G16电脑一开机之后&#xff0c;电脑屏幕就变成了绿色的&#xff0c;无法进行任何的操作。出现这个问题可能是因为电脑中病毒了&#xff0c;或者是系统出现故障。我们可以通过U盘来重新…...

python中关于time模块的讲解---指定格式时间字符串转为时间戳

本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份&#xff0c;取值范围为0001~9999,如1900 %m 月份&#xff08;01~12&#xff09;&#xff0c;例如10 %d 月中的一天&#xff08;01~31&#xff09;例…...

MySql存储引擎与索引

MySql引擎 存储引擎是具体操作数据的地方&#xff0c;是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同&#xff0c;并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...

typing库

typing 库 引入 在日常代码编写中&#xff0c;由于python语言特性&#xff0c;不用像go等编译性语言一样&#xff0c;在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问&#xff0c;这一特性&#…...

linux shell 入门学习笔记10内置shell命令

bash基础的内置命令 echoevalexecexportreadshift echo命令 -n 不换行输出 -e 解析字符串中的特殊符号\n 换行 \r 回车 \t 制表符 四个空格 \b 退格-n参数演示 xiao123xiao123:~/Downloads$ echo 你真胖;echo 你还挺可爱; 你真胖 你还挺可爱 xiao123xiao123:~/Downloads$ ec…...

[动手写操作系统]-02-开机运行系统并打印‘hello‘

文章目录 理解三个概念: 中断interrupts, CPU,寄存器registers 目标:让上一个静默的界面打印一些文本 我们将改进我们的无限循环引导扇区并在屏幕上打印一些东西。我们将为此提出中断。 我们尝试将"Hello"写到寄存器al, 字节0x0e写到ah (the higher part of ax),并…...

Delete `␍`eslint(prettier/prettier) in vscode 的解决方案

错误描述从 Github 仓库拉取代码&#xff0c;使用 vscode 打开&#xff0c;页面报错&#xff0c;每一行都爆红 &#xff08;如下图&#xff09;问题原因由于历史原因&#xff0c;windows下和linux下的文本文件的换行符不一致。Windows在换行的时候&#xff0c;使用了换行符CRLF…...

gof23 设计模式 各个模式代码demo

Gof23 设计模式&#xff0c;也叫Gang of Four&#xff08;GoF&#xff09;设计模式&#xff0c;是由四位设计模式大师&#xff08;Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides&#xff09;撰写的一本书——《设计模式&#xff1a;可复用面向对象软件的基础》所…...

0 初识Kotlin

0 基本介绍 相信很多开发者对Kotlin还是比较陌生的。 Kotlin是一种新型的编程语言&#xff0c;由JetBrains公司开发与设计&#xff0c;在2012年开源&#xff0c; 但没引起什么注意。 直到2017年google宣布将Kotlin作为Android开发的首选语言&#xff0c;Kotlin才开始大放异彩。…...

阿里云服务器部署SpringBoot+Vue项目(宝塔面板傻瓜式操作)

准备工作 一台服务器(我用的是阿里云)SpringBoot项目的jar包Vue项目的dist包 一、购买服务器 然后重置实例密码。 远程连接 登陆成功后安装宝塔面板 二、安装宝塔面板(无账号的注册一个账号) 地址&#xff1a;https://www.bt.cn/new/download.html 选择对应的镜像、不知道…...

27. 移除元素 26. 删除有序数组中的重复项 88. 合并两个有序数组(双指针遍历)

目录[27. 移除元素-力扣](https://leetcode.cn/problems/remove-element/description/?languageTagsc)[26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)[88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-…...

什么时候用std::move()?

文章目录1. "是什么?"2. "有何用?"3. "什么时候用?"1. “是什么?” 虽然 std::move() 从技术角度上是一个函数 &#xff0c;但我认为它不是真正的函数。 它是编译器考虑表达式值的方式之间的转换器。 2. “有何用?” 首先要注意的是 std…...

建立做机器学习项目的范式

建立起做机器学习项目的范式&#xff0c;萃取出核心步骤&#xff0c;避免后面做项目没有明确的方向。 核心步骤&#xff1a; 1、明确自己想做什么样的项目&#xff0c;感兴趣的领域&#xff1b; 2、找到满足项目的数据集&#xff0c;开源的或者自建数据集&#xff1b; 数据…...

搭建k8s高可用集群—20230225

文章目录多master&#xff08;高可用&#xff09;介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…...

Java 修饰符和多态

文章目录一、修饰符1. 权限修饰符2. 状态修饰符2.1 final2.2 static二、多态1. 成员访问特点2. 多态中的转型3. 多态案例一、修饰符 1. 权限修饰符 2. 状态修饰符 2.1 final final 关键字是最终的意思&#xff0c;可以修饰成员方法、成员变量及类。 //1.修饰成员变量 publi…...

学了一年Java的我,想转嵌入式了

秋名山码民的主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f64f;作者水平有限&#xff0c;如发现错误&#xff0c;还请私信或者评论区留言&#xff01; 目录前言为啥我想去转行&#xff1f;如果我现在选择转硬件&#xff0c;我…...

【Git】Git冲突与解决方法

目录 一、Git冲突如何产生&#xff1f; 二、解决Git冲突—手动修改冲突 【第一步】在 hot-fix 分支上增加如下代码&#xff0c;并且提交。 【第二步】在master 分支上同样的地方增加如下代码&#xff0c;并且提交。 【第三步】 我们现在在 master 分支上合并 hot-fix 分支&a…...

深度剖析数据在内存的存储

目录1.深度剖析数据在内存的存储(前言)数据类型介绍类型的基本归类整形在内存中的存储原码、反码、补码大小端练习总结1.深度剖析数据在内存的存储(前言) 今天就让我戴佳伟给大家讲一下数据在内存中的存储。之中有好多让我们深思的点&#xff0c;大家都拿起笔记本&#xff0c;…...

身高排序(绝对值大的排后面,小的排前面)

题目描述 小明今年升学到了小学一年级&#xff0c;来到新班级后&#xff0c;发现其他小朋友身高参差不齐&#xff0c;然后就想基于各小朋友和自己的身高差&#xff0c;对他们进行排序&#xff0c;请帮他实现排序 输入描述 第一行为正整数H和N 0 < H < 200 为小明的身高…...

高频前端面试题之HTML篇(三)

11. label的作用是什么&#xff1f;是怎么用的&#xff1f; label元素不会向用户呈现任何特殊效果&#xff0c;但是&#xff0c;它为鼠标用户改进了可用性&#xff0c;当我们在label元素内点击文本时就会触发此控件。也就是说&#xff0c;当用户选择该标签时&#xff0c;浏览器…...

使用DG备份恢复测试库的流程以及可能出现的问题

使用DG备份恢复测试库的流程以及可能出现的问题 评估数据量和服务器存储空间从DG备库备份全库和归档日志清理测试库环境测试库恢复备份(一)从DG主库备份控制文件测试库恢复备份(二)从DG备库备份最新的归档日志测试库恢复备份(三)需要单独备份数据文件的情况思路:从DG备库…...

Springboot注释解析

SpringBootApplication 标注主程序类 说明一个spring boot应用 SpringBootConfiguration 标注为spring boot配置类 EnableAutoConfiguration 开启自动配置功能 AutoConfigurationPackage 自动配置包 Import({Registrar.class}) 导入一个容器到组件 Registrar.class&#xf…...

C语言之通讯录(动态 存储文件版)

目录 前言 一.基本思路 二.代码的实现 2.1通讯录菜单 2.2通讯录的定义及功能 2.3函数实现 2.3.1初始化通讯录 2.3.2文件信息传递到通讯录里 2.3.3扩容通讯录 2.3.4增加联系人 2.3.5删除联系人 2.3.6查询联系人 2.3.7修改联系人 2.3.8打印通讯录 2.3.9信息保留在文…...

Linux 工具

文章目录一、软件包管理&#xff1a;yum1. 软件的生态环境2. yum 的使用3. yum 源及分类4. 在 centos 7.6 下更新 yum 源到国内镜像5. yum 命令二、编辑器&#xff1a;vim1. 命令模式2. 底行模式3. 插入模式4. 替换模式和视图模式5. vim 配置三、编译器&#xff1a;gcc/g1. C语…...