channel

channel

Go语言在语言级别提供的goroutine间的通信方式,让他们之间可以进行数据交互。

声明方式:

var chanName chan ElementType

// 如:
var ch1 chan int
// 也可以使用make函数创建
ch2 := make(chan string)

上面创建了两个channel,ch1只能用来存储int类型的数据,ch2只能用来存储string类型的数据。

channel的写与读

channel的写与读也非常简单,使用<-符号实现,<-在channel变量名右边表示写入值,<-在左边表示读取值。

如:

ch := make(chan int)
ch <- 10      // 向ch中写入10
res := <-ch   // 读取ch中的值并赋值给res

案例:

package main

import (
    "fmt"
    "time"
    "strconv"
)

func Read(ch chan int){
    for {
        value := <-ch
        fmt.Println("value:" + strconv.Itoa(value))
    }
}
func Write(ch chan int){
    ch <- 10 
}

func main(){
    ch := make(chan int)
    
    go Read(ch)
    go Write(ch)
    time.Sleep(10)
}

输出:

value:10

上面的代码中分别有两个函数,函数Read用来从channel中读取值,函数Write用来往channel里面写值,注意value := <-ch在读取值时可能存在channel中无数据存在的情况,如果没有数据可读就会阻塞,直到从channel中读取到数据。因为会不断从channel中读取可能存在的数据,所以一般都会使用一个死循环来读取channel数据,避免写入channel中的数据会丢失。

channel的操作

channel都有3中操作:send、receive和close

  • send:表示向channel中投放数据
  • receive:表示从channel中读取数据
  • close:表示关闭channel

注意:

  • 关闭channel后,send操作将导致painc(抛出异常)。
  • 关闭channle后,receive操作将返回对应类型的0值以及一个状态码false。
  • close并非强制需要使用,在某些时候可以自动被关闭。
  • 如果使用了close(). 建议条件允许的情况下加上defer
  • 只在send端上显式使用close()关闭channel。因为关闭通道意味着没有数据需要发送。

案例,判断channel是否被关闭:

val, ok := <-ch
if ok{
    fmt.Println(val)
}

缓冲channel

在对channel写入数据后,如果没有读取的操作,程序就会阻塞着不运行,这个时候我们想要程序不阻塞,就可以设置一个缓冲区大小,如果写入值数量超过缓冲区大小时再进行阻塞,声明channel时,可以再跟一个参数,代表缓冲区大小。

声明,如:

c := make(chan int, n)  // n代表缓冲区大小

c := make(chan int)  // 没写参数,代表0 等价于c := make(chan int, 0)

案例:

func test(ch chan int){
    ch <- 10
    fmt.Println("come to goroutine")
}

func main(){
    ch := make(chan int)
    go test(ch)
    time.Sleep(time.Second * 3)
    fmt.Println("runing end")
}

输出结果为:

runing end

因为创建的channel没有设置缓冲区大小,而且在写入值之后也没有读取值的操作,所以程序阻塞,没有打印"come to goroutine"。

修改缓冲区大小,如:

func test(ch chan int){
    ch <- 10
    fmt.Println("come to goroutine")
}

func main(){
    ch := make(chan int,1)
    go test(ch)
    time.Sleep(time.Second * 3)
    fmt.Println("runing end")
}

输出结果为:

come to goroutine
runing end
上一篇:Golang的并发编程(1)


下一篇:让go语言健壮地并发(三)