深入理解golang的channel的使用-日常实战总结no.3

2022-04-25 08:47:09 浏览数 (1)

channel就是所谓的通道:在golang中主要是用于不同于传统的多线程并发模型使用共享内存来实现线程间通信。

1:给一个nil的channel发送数据,会直接服务报错。下面代码是例子

代码语言:javascript复制
package main

import "fmt"

var c chan int


func main() {
fmt.Println(c)
//这里是给一个nil的channel发送数据,会直接服务报错。下面代码是例子
c <- 1
}

下面是返回错误信息:

代码语言:javascript复制
<nil>
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send (nil chan)]:

2:往一个关闭的channel里面发送数据会引起panic,下面代码是例子

代码语言:javascript复制
package main

import "fmt"

func main() {
c := make(chan int)
fmt.Println(c)

//往一个关闭的channel里面发送数据会引起panic,下面代码是例子
close(c)
c <- 1
}

下面是返回的信息

代码语言:javascript复制
0xc0000540c0
panic: send on closed channel

3:往一个关闭的channel里面接受数据,会直接返回 0 ,下面代码是例子

代码语言:javascript复制
package main

import "fmt"

func main() {
c := make(chan int)
fmt.Println(c)

//往一个关闭的channel里面接受数据,会直接返回 0 ,下面代码是例子
close(c)
fmt.Println(<-c)
}

下面是返回的信息

代码语言:javascript复制
0xc0000540c0
0

针对于上面的例子可能你对channel的使用有了深入的了解,下面我们做一下简单的总结:

代码语言:javascript复制
channel的三种状态
nil:未初始化的状态,只进行了声明,或者手动赋值为nil
active:正常的channel,可读或者可写
closed:已关闭,千万不要误认为关闭channel后,channel的值是nil

好了,接下来我们来正确使用channel,带缓冲的和不带缓冲的正确使用。

不带缓冲的正确使用

代码语言:javascript复制
package main

import "fmt"

func main() {
c := make(chan int)
fmt.Println(c)
//这里我们必须从另外一个线程里面写入到通道,然后用主线程或者另外一个线程马上进入等待的状态,这样才能使用无缓冲的channel
//每一个发送者与接收者都会阻塞当前线程,只有当接受者与发送者都准备就绪了
go func() {
        c <- 1
}()
fmt.Println(<-c)
}

下面是返回的信息

代码语言:javascript复制
0xc0000540c0
1

带缓冲的正确使用

代码语言:javascript复制
package main

import "fmt"

func main() {
//chan做限速使用
//不带缓冲的channel写完就阻塞,这种情况只有其他协程中有对应的读才能解除阻塞。而带缓冲长度为N的channel要直到写满 N才阻塞。
//这里channel的发送超出了缓冲的大小,所以会因为阻塞而导致程序死锁,如果设置channel为3,<-1这种写入操作最多为3次,不然会造成死锁。
c := make(chan int, 3)
c <- 1
c <- 2
c <- 3
fmt.Println(<-c)
fmt.Println(<-c)
fmt.Println(<-c)

}

下面是返回的信息

代码语言:javascript复制
1
2
3

0 人点赞