V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
fatbear001
V2EX  ›  问与答

一道 Go 的面试题,答案看不懂,有大佬解释下吗?

  •  
  •   fatbear001 · 2019-10-29 11:16:01 +08:00 · 2021 次点击
    这是一个创建于 1845 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题描述
    使用两个 goroutine 交替打印序列,一个 goroutinue 打印数字, 另外一个 goroutine 打印字母, 最终效果如下 12AB34CD56EF78GH910IJ。
    答案

    chan_n := make(chan bool)
    chan_c := make(chan bool, 1)
    done := make(chan struct{})
    
    go func() {
      for i := 1; i < 11; i += 2 {
        <-chan_c  //这句代码起什么作用?
        fmt.Print(i)
        fmt.Print(i + 1)
        chan_n <- true //这句是往管道里面写数据?有什么用?
      }
    }()
    
    go func() {
      char_seq := []string{"A","B","C","D","E","F","G","H","I","J","K"}
      for i := 0; i < 10; i += 2 {
        <-chan_n // ?
        fmt.Print(char_seq[i])
        fmt.Print(char_seq[i+1])
        chan_c <- true  // ?
      }
      done <- struct{}{} // ?
    }()
    
    chan_c <- true //?
    <-done
    
    8 条回复    2019-10-29 14:12:40 +08:00
    OhYee
        1
    OhYee  
       2019-10-29 11:46:50 +08:00
    <-chan_c 等待管道 chan_c 有数据才继续往下执行
    chan_n <- true 往管道 chan_n 写数据
    <-chan_n 等待管道 chan_n 有数据才继续往下执行
    chan_c <- true 往管道 chan_c 写数据
    done <- struct{}{} 往管道 done 写数据
    <-done 等待管道 done 有数据才往下执行

    总的来说就是两个 goroutine 启动后,都会因为管道为空而阻塞
    在 chan_c <- true 这里,向 chan_c 写入数据,从而导致上面的 goroutine 不再阻塞(读到了 chan_c 的数据。
    输出 1、2 后,向 chan_n 写入数据,并且在下一个循环中由于 chan_c 没有数据而阻塞
    chan_n 读到数据后下面的 goroutine 不再阻塞,开始执行,输出 A、B,并且向 chan_c 写入数据,并且在下一个循环由于 chan_n 没有数据而阻塞
    ……
    重复上面的过程,直到下面的 goroutine 循环结束,向 done 写入数据
    阻塞的主线程在<-done 收到数据,继续执行。后面没代码了,所以结束程序。
    fatbear001
        2
    fatbear001  
    OP
       2019-10-29 11:58:39 +08:00
    @OhYee 按照你所说的:在第二个循环里,chan_c <- true,向 chan_c 写入数据。那既然都向 chan_c 写入数据了,那前面打印字母的代码( fmt.Print(char_seq[i]) fmt.Print(char_seq[i+1]))应该已经执行了吧?不应该先打印字母 AB 吗?我不明白为什么会先打印数字。
    OhYee
        3
    OhYee  
       2019-10-29 12:10:27 +08:00
    1、2 是倒数第二行的 chan_c <- true 触发的
    1、2 后面的 chan_n <- true 触发 A、B
    然后 A、B 后面的 chan_c <- true 触发 3、4
    lmw2616
        4
    lmw2616  
       2019-10-29 12:25:40 +08:00
    先执行的倒数第二行,然后执行打印数字,打印完数字 chan_n 有数据, 才执行打印字母。

    你把倒数第二行改为 chan_n <- true,就是先打印字母了
    lmw2616
        5
    lmw2616  
       2019-10-29 12:29:34 +08:00
    <-chan,chan 没数据就阻塞,有数据就往下执行
    inhzus
        6
    inhzus  
       2019-10-29 12:39:02 +08:00 via Android
    这个是 go 最基础的语法呀… 去学一下 channel 就好了啊
    jessun1990
        7
    jessun1990  
       2019-10-29 14:00:35 +08:00 via Android
    @lmw2616 答案赞同,建议在复习一下 go 中 chan 的使用。强烈推荐 go 高级编程这本书。
    hdbzsgm
        8
    hdbzsgm  
       2019-10-29 14:12:40 +08:00
    都是起 block 作用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2638 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:16 · PVG 19:16 · LAX 03:16 · JFK 06:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.