美文网首页
go语言学习-chan使用过程关于close()

go语言学习-chan使用过程关于close()

作者: 夏海社长 | 来源:发表于2018-08-23 17:26 被阅读0次

    原文地址:https://blog.csdn.net/len_yue_mo_fu/article/details/80315799
    close函数是用于关闭通道的。
    官方解释(摘自close函数源代码注释):

    The close built-in function closes a channel, which must be either
    bidirectional or send-only. It should be executed only by the sender,
    never the receiver, and has the effect of shutting down the channel after
    the last sent value is received. After the last value has been received
    from a closed channel c, any receive from c will succeed without
    blocking, returning the zero value for the channel element. The form
    x, ok := <-c
    will also set ok to false for a closed channel.

    翻译过来

    close函数是一个内建函数, 用来关闭channel,这个channel要么是双向的, 要么是只写的(chan<- Type)。
    这个方法应该只由发送者调用, 而不是接收者。
    当最后一个发送的值都被接收者从关闭的channel(下简称为c)中接收时,
    接下来所有接收的值都会非阻塞直接成功,返回channel元素的零值。
    如下的代码:
    如果c已经关闭(c中所有值都被接收), x, ok := <- c, 读取ok将会得到false。

    chan在go语言中相当于一个文件操作符,使用完成之后需要使用Close()函数关闭。

    下面这段代码有两个chan,ch1是一个chan int类型,ch2是一个chan bool类型,ch1被write()函数写入10个数,被read()函数读取,ch2其实是为了防止main所在的goroutine提前退出用的。

    我们分别在写完之后Close()和不Close()看看有什么不同。

    package main
    
    import "fmt"
    
    func read(ch1 chan int,ch2 chan bool){
        for{
            fmt.Printf("read a int is %d\n",<-ch1)
        }
        ch2 <- true
    }
    
    func write(ch chan int){
        for i:=0;i<10;i++{
             ch <- i
        }
        //close(ch)
    }
    
    func main() {
        ch1 := make(chan int)
        ch2 := make(chan bool)
    
        go write(ch1)
        go read(ch1,ch2)
    
        <-ch2
    }
    

    下面是不close()的运行结果:


    20180514212318221.png

    从执行结果可以看到,当我们将10个数写完之后,如果不close()ch1,read就会阻塞,程序中所有的协程都被阻塞,ch2无法写入,也无法读取,系统这时候检测到这种错误就会报错。
    当我们把close()打开之后,再执行一遍,看看运行的结果:

    20180514213349205.png

    我们这次可以看到close之后,read函数在读完10个数字之后,也不会阻塞会一直读取到0,ch2也不会因为没有写入和读取导致整个程序报错。所以我们每次在使用chan完成之后一定要记得关闭,这样即使我们读端没有做读完处理,程序也不会出错。
    下面是这个例子的正确写法,我们在读取chan时可以根据,第二个返回值,判断写端是否关闭,如果写端关闭,则会读取到false,通过close()和读取端根据读chan第二个返回值可以确保管道在读写两端能够做到写多少读多少,程序也能很友好的退出。

    package main
    
    import "fmt"
    
    func read(ch1 chan int,ch2 chan bool){
        for{
            v ,ok:= <- ch1
            if ok{
                fmt.Printf("read a int is %d\n",v)
            }else{
                ch2 <- true
            }
        }
    
    }
    
    func write(ch chan int){
        for i:=0;i<10;i++{
             ch <- i
        }
        close(ch)
    }
    
    func main() {
        ch1 := make(chan int)
        ch2 := make(chan bool)
    
        go write(ch1)
        go read(ch1,ch2)
    
        <-ch2
    }
    

    下面是执行结果:


    20180514214103652.png

    注意事项:
    对于值为nil的channel或者对同一个channel重复close, 都会panic, 关闭只读channel会报编译错误。

    相关文章

      网友评论

          本文标题:go语言学习-chan使用过程关于close()

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