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…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

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

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...

论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...