c语言编程笔录

首页 >   > 笔记大全

笔记大全

Go中的channel怎么声明和使用

更新时间:2023-11-27

声明和初始化channel

在Go中使用make函数声明并初始化一个channel:

ch := make(chan int)  // 声明一个int类型的channel

channel不仅可以传递基本数据类型,还可以传递复合数据类型和自定义数据类型:

ch1 := make(chan []byte)  // 声明一个字节切片类型的channel
type Person struct {
    name string
    age  int
}
ch2 := make(chan Person)  // 声明一个自定义结构体类型的channel

向channel发送和读取数据

使用<-运算符将数据发送到channel,并使用<-运算符从channel中读取数据:

ch := make(chan int)
go func() {  // 启动独立的协程发送数据到channel
    for i := 0; i < 10; i++ {
        ch <- i  // 向channel发送数据
    }
    close(ch)  // 关闭channel,表示数据发送完毕
}()
for x := range ch {  // 从channel中读取数据
    fmt.Println(x)
}

channel的容量和阻塞

channel还有容量的限制,使用make函数时可以指定容量,如果未指定容量,则默认容量为0:

ch := make(chan int, 10)  // 声明一个容量为10的int类型channel

如果向一个容量为0且没有读取者的channel发送数据,发送者的协程会被阻塞,直到channel中有读取者读取数据为止。反之,如果读取一个空的channel,读取者的协程也会被阻塞,直到channel中有数据可读为止。以下是一个例子:

ch := make(chan int)
go func() {  // 启动独立的协程发送数据到channel
    for i := 0; i < 10; i++ {
        ch <- i  // 向channel发送数据
    }
    close(ch)  // 关闭channel,表示数据发送完毕
}()
for {  // 从channel中读取数据
    x, ok := <-ch
    if !ok {  // 如果channel已关闭,则退出循环
        break
    }
    fmt.Println(x)
}

select语句和超时控制

使用select语句可以监听多个channel,一旦其中有一个channel可读或可写,就会执行相应的分支:

ch1 := make(chan int)
ch2 := make(chan int)
go func() {  // 启动独立的协程向ch1发送数据
    for i := 0; i < 10; i++ {
        ch1 <- i
    }
}()
go func() {  // 启动独立的协程向ch2发送数据
    for i := 100; i < 110; i++ {
        ch2 <- i
    }
}()
for i := 0; i < 20; i++ {  // 读取ch1或ch2发送的数据
    select {
    case x := <-ch1:
        fmt.Println("ch1:", x)
    case x := <-ch2:
        fmt.Println("ch2:", x)
    }
}

select语句中也可以利用time包的定时器来实现超时控制:

ch := make(chan int)
go func() {  // 启动独立的协程向ch发送数据
    time.Sleep(time.Second * 3)
    ch <- 1
}()
select {  // 等待3秒钟,如果ch有数据可读,则读取数据,否则超时退出
case x := <-ch:
    fmt.Println(x)
case <-time.After(time.Second * 3):
    fmt.Println("timeout")
}

总结

Go中的channel是一种用于协程间通信和数据共享的重要机制,其操作具有原子性和同步性,能够有效避免竞态条件和死锁问题。使用channel时需要注意以下几点:

  • 使用make函数声明并初始化channel时可以指定容量,未指定容量时默认容量为0。
  • 向channel发送数据使用<-运算符,从channel读取数据也使用<-运算符,获取到的数据类型和发送的数据类型要一致。
  • 除非不再向channel中发送数据,否则不要手动关闭channel,因为channel的关闭是一种广播机制,所有读取者在读取完数据后会立即获取到通信状态为关闭的信息。
  • 当向一个容量为0且没有读取者的channel发送数据或从一个容量为0且没有数据可读的channel读取数据时,发送者或读取者的协程会被阻塞,直到channel中有读取者或发送者为止。
  • 使用select语句可以监听多个channel,一旦其中有一个channel可读或可写,就会执行相应的分支。通过select语句和time包的定时器结合,还可以实现超时控制。