1. channel 的设计模式CSP是什么?
1.1 CSP是什么?对于传统的共享内存有什么好处?
- CSP:Communicating Sequential Processes,顺序通信进程,核心就是多个线程之间通过channel来进行通信。这个也对应golang社区的一句经典语 不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存
- 这种设计模式带来的好处有哪些(对比共享内存)?
- 解耦合,通过数据冗余来避免程序员频繁直接操作 锁,降低编码复杂度
- 便于分布式通信(目前在golang channel没有体现)
1.2 对比 并发模型 Actor 和 CSP
- 什么是Actor?
- Actor模式是一种并发模型,与另一种模型共享内存完全相反,Actor模型share nothing。所有的线程(或进程)通过消息传递(邮箱)的方式进行合作,这些线程(或进程)称为Actor
- actor 和 CSP 对比图 ?第一张图为actor 第二张为 channel
- csp模型和actor模型有什么区别
- CSP 通信中goroutine是和channel 解耦合的,actor 和 传递消息的 “邮箱” 是耦合的
- CSP 通信是同步的,Actor则是异步的。golang中channel是进行优化后支持缓存
- CSP 通信中通过channel通信的两个goroutine,由于有channel的存在,所以相互是匿名的,而Actor中的Actor实例则不是
- CSP 模型能够保证顺序性,而Actor模型不行。比如 当生产为 一个 ,而消费者为多个的时候
2. channel 底层结构是什么样的 ?
- 具体channel里面的各种功能可以参考源码runtime/chan.go:
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
3. channel使用中遇到过的问题有哪些?怎么解决?
3.1 向一个关闭了的channel写入了数据, 导致Panic
- 解决办法1: 写入的goroutineshi来关闭channel,而不是由读取的channel来进行关闭
- 解决办法2: 当遇到多个写入的groutine的时候,通过sync.waitGroup来进行阻塞关闭
3.2 一个有缓存的channel已经关闭,还是能够读取到数据
- 要考虑兼容此类情况,不能说已经close掉了channel就一定没有数据了,代码如下
package main
import (
"fmt"
"testing"
"time"
)
func OnlyRead(testCh <-chan string) {
result, ok := <-testCh
fmt.Println(result, ok) // 这里会输出:msg1 true
}
func TestChannel(t *testing.T) {
testCh := make(chan string, 5)
testCh <- "msg1"
close(testCh)
go OnlyRead(testCh)
time.Sleep(time.Second)
}
3.3 某个函数中对channel进行写入又对channel进行读取,导致复杂度提升
- 通过传参进行限制只读或者是只写,代码如下
package main
import (
"fmt"
"testing"
"time"
)
func OnlyWrite(testCh chan<- string) {
testCh <- "msg2"
}
func OnlyRead(testCh <-chan string) {
for result := range testCh {
fmt.Println(result, "====")
}
}
func TestChannel(t *testing.T) {
testCh := make(chan string, 2)
testCh <- "msg1"
go OnlyRead(testCh)
go OnlyWrite(testCh)
time.Sleep(time.Second * 1)
close(testCh)
}
4. 参考链接
csp 和 actor的区别: