Golang中的Channel

goroutine和goroutine之间通过channel通信

channel的创建

1 使用make创建

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

c := make(chan int)

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

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

2 使用var创建

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

var c chan int  // 此时c为nil

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

var channels [10]chan int

channel的传与收

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

c <- 1
c <- 2

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

较完整的示例片段如下:

// 创建一个channel
c := make(chan int)

// 起一个goroutine,用来接收channel中的数据并打印
go func() {
    for {
        n := <-c
        fmt.Println(n)
    }
}()

// 向channel中传数据
c <- 1
c <- 2

// 这里加个sleep,是为了避免channel中的数据还没打印,main函数就退出了
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判断

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

方法(2): 通过range

for n := range c {
    ...
}

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

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

例:

package main

import (
	"fmt"
	"sync"
)

func doWork(id int,
	w worker) {
	for n := range w.in {
		fmt.Printf("Worker %d received %c\n",
			id, n)
		w.done()
	}
}

type worker struct {
	in   chan int
	done func()
}

func createWorker(
	id int, wg *sync.WaitGroup) worker {
	w := worker{
		in: make(chan int),
		done: func() {
			wg.Done()
		},
	}
	go doWork(id, w)
	return w
}

func chanDemo() {
	var wg sync.WaitGroup

	var workers [10]worker
	for i := 0; i < 10; i++ {
		workers[i] = createWorker(i, &wg)
	}

	wg.Add(20)
	for i, worker := range workers {
		worker.in <- 'a' + i
	}
	for i, worker := range workers {
		worker.in <- 'A' + i
	}

	wg.Wait()
}

func main() {
	chanDemo()
}

select的使用

例:

var c1, c2 chan int
select {
case n := <-c1:
    fmt.Println("received from c1:", n)
case n := <-c2:
    fmt.Println("received from c2:", n)
default:
    fmt.Println("no value received")
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值