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 {
			m := <-ch
			fmt.Print(m)
			fmt.Println("goroutine2")
			
            // 将数据递给下一个goroutine
            ch <- m
		}
	}()

	// goroutine3
	go func() {
		for {
			m := <-ch
			fmt.Print(m)
			fmt.Println("goroutine3")
			
			// 将数据递给下一个goroutine
			ch <- m
		}
	}()

	for {
		scan.Scan()
        // 开始传递数据
		ch <- fmt.Sprintf("%d : Hello ", i)
		
		/* 同时到队伍后取数据,终止向后继续传递 */ 
		<-ch
		
		i++
	}
}

你可能感兴趣的:(golang中使用一个通道向多个goroutine发送一个数据)