Golang中的Channel

旧城等待, 2023-07-20 08:18 78阅读 0赞

goroutine和goroutine之间通过channel通信

channel的创建

1 使用make创建

channel创建可以用make方法,如:

  1. c := make(chan int)

此外,如果make方法第二个参数多写一个数字,则表示对channel作buffer缓冲:

  1. // 表示channel中每接收3个后再给接收者
  2. c := make(chan int, 3)

2 使用var创建

不用make的话,也可以用var:

  1. var c chan int // 此时c为nil

如果创建channel数组,则写法如下:

  1. var channels [10]chan int

channel的传与收

往创建好的channel中传数据使用<-表示,如:

  1. c <- 1
  2. c <- 2

注意:往channel传数据后必须要有接收者,否则程序运行会报deadlock

较完整的示例片段如下:

  1. // 创建一个channel
  2. c := make(chan int)
  3. // 起一个goroutine,用来接收channel中的数据并打印
  4. go func() {
  5. for {
  6. n := <-c
  7. fmt.Println(n)
  8. }
  9. }()
  10. // 向channel中传数据
  11. c <- 1
  12. c <- 2
  13. // 这里加个sleep,是为了避免channel中的数据还没打印,main函数就退出了
  14. time.Sleep(time.Millisecond)

channel可作参数和返回值

channel可以作为参数传递,也可以作返回值。

需要注意的是,channel作为收数据还是发数据,写法是不一样的。
chan<- int 和<-chan int这两个是有区别的:

  • chan<- int表示send only,只能往里发
  • <-chan int表示revice only,只能从里收

channel的close

发送方可以使用close©方法来关闭channel,以告诉接收方没有新数据了。
channel关闭后,接收者还能接收数据不会报错,不过接收到的是对应类型的零值

如何判断channel是否关闭?
方法(1): 通过if判断

  1. n, ok := <-c
  2. if !ok {
  3. fmt.Println("channel 没有数据了")
  4. break
  5. }

方法(2): 通过range

  1. for n := range c {
  2. ...
  3. }

使用sync.WaitGroup等待goroutine任务结束

之前使用time.Sleep(time.Millisecond)的方式来让main函数等待任务完成,但是不太好。
golang中提供了sync.WaitGroup方法来实现这个功能

例:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. func doWork(id int,
  7. w worker) {
  8. for n := range w.in {
  9. fmt.Printf("Worker %d received %c\n",
  10. id, n)
  11. w.done()
  12. }
  13. }
  14. type worker struct {
  15. in chan int
  16. done func()
  17. }
  18. func createWorker(
  19. id int, wg *sync.WaitGroup) worker {
  20. w := worker{
  21. in: make(chan int),
  22. done: func() {
  23. wg.Done()
  24. },
  25. }
  26. go doWork(id, w)
  27. return w
  28. }
  29. func chanDemo() {
  30. var wg sync.WaitGroup
  31. var workers [10]worker
  32. for i := 0; i < 10; i++ {
  33. workers[i] = createWorker(i, &wg)
  34. }
  35. wg.Add(20)
  36. for i, worker := range workers {
  37. worker.in <- 'a' + i
  38. }
  39. for i, worker := range workers {
  40. worker.in <- 'A' + i
  41. }
  42. wg.Wait()
  43. }
  44. func main() {
  45. chanDemo()
  46. }

select的使用

例:

  1. var c1, c2 chan int
  2. select {
  3. case n := <-c1:
  4. fmt.Println("received from c1:", n)
  5. case n := <-c2:
  6. fmt.Println("received from c2:", n)
  7. default:
  8. fmt.Println("no value received")
  9. }

注意:通过var方式声明的c1和c2默认是nil,但用select方式并不会报错,因为有default兜底。
如果这里没有default,程序则会报deadlock,因为这里只有接收者,没有channel的发送者

发表评论

表情:
评论列表 (有 0 条评论,78人围观)

还没有评论,来说两句吧...

相关阅读

    相关 golangchannel基本介绍

    1、goroutine是运行在相同的的地址空间,因此访问共享内存必须做好同步,goroutine奉行通过通信来共享内存,而不是共享内存来通信 2、channel是引用类

    相关 golangchannel超时

    基本语法 通道声明和初始化 我们可以通过`chan`关键字来声明通道类型变量 var ch chan int // 声明一个通道类型变量 ch,并且通道

    相关 golang channel 使用

    本文对channel使用中的几个疑惑,以例子的形式加以说明。 普通channel 缺省情况下,发送和接收会一直阻塞着,直到另一方准备好. 例如: pack

    相关 golangChannel

    Channel是Go中的一个核心类型,可以将其看成一个管道,通过它并发单元就可以发送或者接收数据进行通信(communication)。 `Do not communicat