美文网首页
go channel

go channel

作者: n_xy | 来源:发表于2021-04-10 13:20 被阅读0次

channel

channel一般用于goroutine之间的通信;初始化chan :=make(chan int)
可以比较:同一引用的chan比较返回true,可以用于map的key

3种操作:
  1. 发送
    chan <- x,对一个关闭的通道发送数据会导致panic
  2. 接受
    x <- chan,对关闭的通道的接收操作会立即返回获取一个通道类型的零值
  3. 关闭
  • 重复关闭 channel 会导致 panic。
  • 向关闭的 channel 发送数据会 panic。
  • 从关闭的 channel 关读数据不会 panic,读出 channel 中已有的数据之后再读就channel 类似的默认值,比如 chan int 类型的 channel 闭之后读取到的值为 0。

对于上述第三点,有个点需要注意:从channel中读出的是是默认零值还是channel关闭了返回的值.可以用类似map中取值的方式判断

ch := make(chan int, 10)
...
close(ch)

// ok-idiom 
val, ok := <-ch
if ok == false {
    // channel closed
}

类型

通道不是必须要关闭的,gc回收取决于是否可以访问

  1. 无缓冲通道
    接收操作会阻塞,直到另一头执行发送,当通道关闭接收操作理解返回。同时所有类型通道在关闭后发送操作会引发panic,接收操作会立即返回一个零值(用在取消goroutine上)
    可以使用以下方式来判断通道是否关闭
 data ,ok := <- chan, ok

通道也可用于range

  1. 单向通道
    func a(<- chan int) ,该通道只能接收数据
    func a( chan<- int) ,该通道只能发送数据
    非法操作会在编译时报错

其实这两种通道被声明时都是chan类型的,只不过在函数中为了限定行为而加入的限制.

  1. 缓冲通道
    make(chan int ,3)
    上述通道可以看做容量为1的缓冲通道,用作队列,关闭后允许接收完通道中的数据

案例 & 用法

一般select只会走一次,break基本上没什么作用,所以一般要配合for循环使用, break 跳出外循环

out:    for {
            select {
            case e, ok := <-c1:
            ...
            break out
            case e, ok := <-c2:
            ...
            }

for range

func producer(ch chan int) {
 for _, v := range values {
     ch <- v
 }  
}

超时

select {
  case <- ch:
    // get data from ch
  case <- time.After(2 * time.Second)
    // read data from ch timeout
}

goroutine泄露

func a ()  {
    pipe := make(chan int)
    go func(){ <-pipe}
    pipe <- 1
    pipe <- 2
    pipe <- 3
    //fatal error: all goroutines are asleep - deadlock!
}

函数执行完后会有两个 goroutine卡住,无法被回收,叫goroutine泄露。办法是改成缓冲通道

而且修改下代码

func a ()  {
    pipe := make(chan int,3)
    go func(){ <-pipe}
    pipe <- 1
    pipe <- 2
    pipe <- 3
    //fatal error: all goroutines are asleep - deadlock!
}

channel都需要对应的接收者和发送者,如果已经明确的缺少了一端(事实上已经不可能在发送或接收数据了)就会爆出上述错误;而第一段代码会安全退出是因为main本来不会等待其他协程,因为通道操作而阻塞,等到接收到第一个数字时就会退出不会等待其他协程发送.

取消goroutine

通过chan的广播方式,确切的说是关闭通道接收操作会立即返回的特点.在各个goroutine中接收一个chan,当需要停止时,关闭这个chan,这些goroutine就会收到取消信号.

channel 读写

当channel的接收两端一端在接收而通道中没有值,且没有另一端再发送数据(没有可能发送数据的代码了),会出错

IO

IO包

Reader
type Reader interface {
 Read(p []byte) (n int, err error) 
}

读取len(p)字节写入p。
当读入数据不足len(p)时,会返回能够读取的数据,而不会继续等待
当遇到错误或者到达末尾时,会返回读取的字节数以及一个错误,当读到末尾时,err返回一个EOF或者nil。但不管如何,发生这两种情况下次调用读入长度肯定为(0,EOF)。所以要求每次都要读入的字节。

ReaderAt
type ReaderAt interface { 
ReadAt(p []byte, off int64) (n int, err error)
   }

从底层输入流读取off偏移量位置len(p)的数量的字节。
方法会等待读满返回,当n<len(p)时,会返回err中说明为啥没读满。
方法不会改变底层流的状态。

Writer
type Writer interface { 
  Write(p []byte) (n int, err error)
}

写入操作。
返回写入的字节数以及导致写入提前结束的错误。

WriteAt
type WriterAt interface { 
WriteAt(p []byte, off int64) (n int, err error) 
}

可以并行写入的方法
也是返回写入长度以及导致提前结束的错误。
操作不会影响底层流的偏移量。

相关文章

  • 文章收藏

    channel Go Channel 详解

  • Golang Channel底层实现

    Go Channel 底层实现 目录 channel 是什么 channel 的创建 channel 的发送 ch...

  • 26.Go语言·管道Channel

    main.go model/Channel.go

  • Go语言——channel详解

    Go语言——channel详解 channel和goroutine是go语言最具特色是结构,有必要仔细研究。 源码...

  • channel in Go's runtime

    http://skoo.me/go/2013/09/20/go-runtime-channel/

  • Go channel

    单纯地将函数并发执行是没有意义的,函数与函数之间需要交换数据才能体现并发执行函数的作用。虽然可使用共享内存进行数据...

  • go channel

    [toc] Channel 编译器翻译 关键数据结构 hchan sudog hchan sudog 其中buf ...

  • go channel

    浅析 go channel channel 是 goroutine 之间通信的一种方式,可以类比成 Unix 中的...

  • go channel

    channel channel一般用于goroutine之间的通信;初始化chan :=make(chan int...

  • Go - Channel

    设计理念 执行业务处理的 goroutine 不要通过共享内存的方式通信,而是要通过 Channel 通信的方式分...

网友评论

      本文标题:go channel

      本文链接:https://www.haomeiwen.com/subject/azbbhltx.html