golang中使用一个通道向多个goroutine发送一个数据 - Go语言中文社区

golang中使用一个通道向多个goroutine发送一个数据


向一个goroutine通信

向通道发送一次消息只有一个goroutine能收到数据,goroutine向一个通道取数据类似于银行里一个柜台排队取钱,goroutine是那排在长长的队伍,一个通道(channel)就是一个柜台,只有等前一个goroutine取完数据之后,后一个goroutine才能取下一个数据。

  • 一个goroutine循环接收

golang中向一个goroutine只需将值传入通道中,然后在goroutine里从这个通道取值即可,由于只有一个goroutine在循环接收数据,相当于队伍中只有一个人,取完数据之后可以继续站在柜台前等待,例如:

package main

import (
"bufio"
"os"
)

func main() {
  ch, scan:= make(chan string),bufio.NewScanner(os.Stdin)

  // goroutine1
  go func() {
    for {
      fmt.Println(<-ch)
      fmt.Println("goroutine1")
    }
  }()

  // 按一次回车向通道发送一条消息
  for {
  scan.Scan()
  ch <- "Hello goroutine"
  }
}

向通道放入数据时确保有goroutine正在等待着这个通道的数据,若这个通道没有goroutine等待数据则会报错。

fatal error: all goroutines are asleep - deadlock!

  • 多个goroutine循环接收数据

例如这个代码例子,每点一次回车向一个通道发送一次数据,但是一次只能有一个goroutine收到数据。如果接收完数据之后想要再次从这个通道接收数据则需要到队伍的最后重新排队等待。

package main

import (
"bufio"
"fmt"
"os"
)

func main() {
  i, ch, scan := 0, make(chan string), bufio.NewScanner(os.Stdin)
  // goroutine1
  go func() {
    for {
    fmt.Print(<-ch)
    fmt.Println("goroutine1")
  }
}()

// goroutine2
go func() {
  for {
    fmt.Print(<-ch)
    fmt.Println("goroutine2")
  }
}()
  
// goroutine3
  go func() {
    for {
      fmt.Print(<-ch)
      fmt.Println("goroutine3")
    }
  }()

  for {
    scan.Scan()
    ch <- fmt.Sprintf("%d : Hello ", i)
    i++
  }
}

多个goroutine同时接收通道的一条消息

原理很简单,举个例子:假如柜台前所有的人都要看一张通知单,柜员A在柜台前将通知单递给第一个人时,安排柜员B排到队伍的最后;队伍中的第一个人看完通知单后将通知单递回柜台,然后到队伍的最后重新排队(此时排在柜员B的后面),接着下一个人重复第一个人的操作,直到柜员B排到柜台前拿走通知单,走回柜台里(不将通知单给下一个人)。这样第一个看通知单的人重新回到柜台前等待下一个数据。

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
  i, ch, scan := 0, make(chan string), bufio.NewScanner(os.Stdin)
  
  // goroutine1
  go func() {
    for {

      /* 获取通道里的数据 */
      m := <-ch
      fmt.Print(m)
      fmt.Println("goroutine1")

      /* 处理完成之后将数据通过通道递给下一个goroutine
      ch <- m
    }
  }()

  // goroutine2
  go func() {
    for {
      
      /* 此处处理同goroutine1 */
      m := <-ch
      fmt.Print(m)
      fmt.Println("goroutine2")
      ch <- m
    }
  }()

// goroutine3
  go func() {
    for {
      m := <-ch
      fmt.Print(m)
      fmt.Println("goroutine3")
      ch <- m
    }
  }()

  for {
    scan.Scan()
    
    /* 按下一次回车向通道发送一次数据 */
    ch <- fmt.Sprintf("%d : Hello ", i)
    
    /* 向通道里传递数据后立即到队伍后面重新排队 */ 
    <-ch
    i++
  }
}

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/faf9e536de3c
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-01-12 12:50:48
  • 阅读 ( 1869 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢