当前位置: 首页 > 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…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

Python爬虫实战:研究Restkit库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...

Redis上篇--知识点总结

Redis上篇–解析 本文大部分知识整理自网上&#xff0c;在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库&#xff0c;Redis 的键值对中的 key 就是字符串对象&#xff0c;而 val…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...