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的基本介绍: 在前端开发中:HTML是用来显示数据,而XML是用来传输和存储数据的 XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种标记语言,很类似 HTMLXML 的设计宗旨是传输数据,而…...

网络应用之URL
URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。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设置,修改advanced参数: boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled(其他电脑是修改硬盘的SATA和ACHI模式)。但是改了之后windo…...

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?
机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?最近有用户使用的机械革命旷世G16电脑一开机之后,电脑屏幕就变成了绿色的,无法进行任何的操作。出现这个问题可能是因为电脑中病毒了,或者是系统出现故障。我们可以通过U盘来重新…...
python中关于time模块的讲解---指定格式时间字符串转为时间戳
本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份,取值范围为0001~9999,如1900 %m 月份(01~12),例如10 %d 月中的一天(01~31)例…...
MySql存储引擎与索引
MySql引擎 存储引擎是具体操作数据的地方,是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同,并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...

typing库
typing 库 引入 在日常代码编写中,由于python语言特性,不用像go等编译性语言一样,在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问,这一特性&#…...
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 仓库拉取代码,使用 vscode 打开,页面报错,每一行都爆红 (如下图)问题原因由于历史原因,windows下和linux下的文本文件的换行符不一致。Windows在换行的时候,使用了换行符CRLF…...
gof23 设计模式 各个模式代码demo
Gof23 设计模式,也叫Gang of Four(GoF)设计模式,是由四位设计模式大师(Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides)撰写的一本书——《设计模式:可复用面向对象软件的基础》所…...

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

阿里云服务器部署SpringBoot+Vue项目(宝塔面板傻瓜式操作)
准备工作 一台服务器(我用的是阿里云)SpringBoot项目的jar包Vue项目的dist包 一、购买服务器 然后重置实例密码。 远程连接 登陆成功后安装宝塔面板 二、安装宝塔面板(无账号的注册一个账号) 地址: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() 从技术角度上是一个函数 ,但我认为它不是真正的函数。 它是编译器考虑表达式值的方式之间的转换器。 2. “有何用?” 首先要注意的是 std…...

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

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

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...