iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang协程常见面试题代码分析
  • 805
分享到

Golang协程常见面试题代码分析

2023-07-05 07:07:09 805人浏览 独家记忆
摘要

这篇文章主要介绍“golang协程常见面试题代码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Golang协程常见面试题代码分析”文章能帮助大家解决问题。交替打印奇数和偶数使用两个gorouti

这篇文章主要介绍“golang协程常见面试题代码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“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{}) //无缓冲channel    defer close(ch)    maxVal := 100    go 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 := 20    go func() { //奇数协程        defer wg.Done()        for i := 1; i <= maxVal; i += 2 {            <-oddChan            fmt.Printf("the odd print %d\n", i)            eveChan <- struct{}{} //通知偶数协程        }    }()    go func() {        //偶数协程        defer wg.Done()        for i := 2; i <= maxVal; i += 2 {            <-eveChan            fmt.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 := 10    res := 0                        //用于打印数字    N := 3                          //协程的数量    exitChan := make(chan struct{}) //用于退出    chanArr := make([]chan struct{}, N)    for i := 0; i < N; i++ {        //使用无缓冲的channel        chanArr[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)    }    <-exitChan    for 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.WaitGroup    wg.Add(2)    numChan <- struct{}{}    go func() {        defer wg.Done()        for num := 1; num <= 26; num++ {            <-numChan            fmt.Printf("%d", num)            chChan <- struct{}{}        }    }()    go func() {        defer wg.Done()        for ch := 'A'; ch <= 'Z'; ch++ {            <-chChan            fmt.Printf("%s", string(ch))            numChan <- struct{}{}        }    }()    wg.Wait()}

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

    func main() {    numChan := make(chan struct{})    defer close(numChan)    var wg sync.WaitGroup    wg.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++ {            <-numChan            fmt.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++ {            <-chChan            if 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 := 0    maxVal := 10    exitChan := make(chan struct{}) //用于退出    go func() {        for {            <-Achan            if counter >= maxVal {                exitChan <- struct{}{}                break            }            fmt.Printf("%s ", "A")            counter++            Bchan <- struct{}{}        }    }()    go func() {        for {            <-Bchan            if counter >= maxVal {                exitChan <- struct{}{}                break            }            fmt.Printf("%s ", "B")            counter++            Cchan <- struct{}{}        }    }()    go func() {        for {            <-Cchan            if 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个数发送到ch2管道当中,再启动一个协程从ch2当中取值然后计算平方将其放入ch3管道当中主协程打印

    package mainimport (    "fmt"    "sync")var wg sync.WaitGroupfunc f1(ch2 chan int) {    defer wg.Done()    for i := 0; i < 50; i++ {        ch2 <- i    }    close(ch2)}func f2(ch3 chan int, ch2 chan int) {    defer wg.Done()    defer close(ch3)    for x := range ch2 {        ch3 <- 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协程常见面试题代码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网GO频道,小编每天都会为大家更新不同的知识点。

    您可能感兴趣的文档:

    --结束END--

    本文标题: Golang协程常见面试题代码分析

    本文链接: https://www.lsjlt.com/news/350276.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Golang协程常见面试题代码分析
      这篇文章主要介绍“Golang协程常见面试题代码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Golang协程常见面试题代码分析”文章能帮助大家解决问题。交替打印奇数和偶数使用两个gorouti...
      99+
      2023-07-05
    • Golang协程常见面试题小结
      目录交替打印奇数和偶数方法一:使用无缓冲的channel进行协程间通信方法二:使用有缓冲的channelN个协程打印1到maxVal交替打印字符和数字交替打印字符串方法一使用无缓冲的...
      99+
      2023-02-28
      Golang协程面试题 Golang协程
    • 常见angular面试题实例分析
      本篇内容主要讲解“常见angular面试题实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“常见angular面试题实例分析”吧!1、angular 的数据...
      99+
      2022-10-19
    • web前端常见面试题实例分析
      这篇文章主要介绍“web前端常见面试题实例分析”,在日常操作中,相信很多人在web前端常见面试题实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”web前端常见面试题实例...
      99+
      2022-10-19
    • PHP面试题实例代码分析
      本篇内容主要讲解“PHP面试题实例代码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP面试题实例代码分析”吧!Q1: == 和 === 之间有什么区别?话题: PHP困难: ⭐如果是两个...
      99+
      2023-06-30
    • JavaScript面试题实例代码分析
      这篇文章主要介绍了JavaScript面试题实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript面试题实例代码分析文章都会有所收获,下面我们一起来看看...
      99+
      2022-10-19
    • CSS面试题实例代码分析
      这篇文章主要介绍了CSS面试题实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇CSS面试题实例代码分析文章都会有所收获,下面我们一起来看看吧。简单的代码如下:Firs...
      99+
      2022-10-19
    • TS面试题实例代码分析
      本篇内容主要讲解“TS面试题实例代码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“TS面试题实例代码分析”吧!第一层的要求是这样的:实现一个 zip 函数,对两个数组的元素按顺序两两合并,比...
      99+
      2023-07-05
    • 前端react面试题实例代码分析
      这篇“前端react面试题实例代码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“前端react面试题实例代码分析”文章吧...
      99+
      2023-07-05
    • vue核心面试题实例代码分析
      这篇文章主要介绍了vue核心面试题实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue核心面试题实例代码分析文章都会有所收获,下面我们一起来看看吧。1-为什么要在列表中绑定key,有什么作用&nbs...
      99+
      2023-07-04
    • web前端面试题实例代码分析
      这篇文章主要讲解了“web前端面试题实例代码分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“web前端面试题实例代码分析”吧!面试官:给定一个元素,如何实现水平垂直居中?我:呃~,针对这个...
      99+
      2023-07-05
    • web前端面试题案例代码分析
      这篇文章主要讲解了“web前端面试题案例代码分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“web前端面试题案例代码分析”吧!面试官:css 如何实现左侧固定 300px,右侧自适应的布局...
      99+
      2023-07-05
    • jQuery常见面试题之DOM操作的示例分析
      这篇文章主要为大家展示了“jQuery常见面试题之DOM操作的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“jQuery常见面试题之DOM操作的示例分析...
      99+
      2022-10-19
    • web前端面试问答题实例代码分析
      这篇文章主要介绍“web前端面试问答题实例代码分析”,在日常操作中,相信很多人在web前端面试问答题实例代码分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”web前端面试问答题实例代码分析”的疑惑有所帮助!...
      99+
      2023-07-05
    • web前端高频面试题实例代码分析
      本篇内容介绍了“web前端高频面试题实例代码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!面试官:请你谈谈JS的this指向问题我:呃~...
      99+
      2023-07-05
    • 【整理分享】一些常见Vue面试题(附答案解析)
      本次给大家分享一些关于Vue的常见面试题,带你梳理基础知识,增强Vue知识储备,值得收藏,快来看看吧!Vue 常见面试题总结MVVM模型?MVVM,是Model-View-ViewModel的简写,其本质是MVC模型的升级版。其中 Mode...
      99+
      2023-05-14
      面试 Vue.js
    • Java面试Socket编程常用参数设置源码问题分析
      目录引导语1、Socket 整体结构2、初始化3、connect 连接服务端4、Socket 常用设置参数4.1、setTcpNoDelay4.2、setSoLinger4.3、se...
      99+
      2022-11-13
    • Go 编程算法面试:LeetCode 中的常见问题解析
      LeetCode 是一家著名的面试准备网站,提供了大量的编程算法题目,对于想要在面试中脱颖而出的程序员来说,这些题目是必须掌握的。Go 作为一门越来越受欢迎的编程语言,其在 LeetCode 中的应用也日益广泛。本文将为大家介绍一些 Le...
      99+
      2023-07-08
      编程算法 面试 leetcode
    • ES6中Promise、async和await面试题实例代码分析
      这篇“ES6中Promise、async和await面试题实例代码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“ES6中...
      99+
      2023-07-05
    • 好程序员Java教程分享:Java工程师常见面试题
        好程序员Java教程分享:Java工程师常见面试题  一:BigInteger  (1)针对大整数的运算:可以让超过Integer范围内的数据进行运算。  (2)构造方法  A:BigInteger(String s)  (3)成员方法...
      99+
      2023-06-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作