// todo 见参考1,2
切片和数组区别:
- 数组值类型,切片引用类型 数组赋值和传参时,整个数组数据都会赋值一遍,消耗掉大量内存
- 数组定长,切片长度可变 切片的内部实现是通过指针引用底层数组
todo : channel什么时候阻塞 golang主协程阻塞实现:
func main() {
ch := make(chan int, 5)
listenCh := make(chan int)
go readNum(ch, listenCh)
for i := 0; i <= 4; i++ {
ch <- i
if i == 4 {
close(ch)
}
}
<-listenCh // 无缓存区且无数据写入 堵塞直至有数据写入
}
func readNum(ch chan int, listenCh chan int) {
for {
if num, ok := <-ch; !ok {
fmt.Println("Channel is closed")
listenCh <- 0
} else {
fmt.Println("num:", num)
}
}
通过golang实现协程交替打印 eg:go1 => 1 3 5 7;go2 => 2 4 6 8 原理:两个协程for循环打印,用两个协程阻塞保证协程交替运行
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
arr1 := []int{1,3,5,7}
arr2 := []int{2,4,6,8}
c := make(chan int, 1) // cd用来堵塞
d := make(chan int, 1)
go func() {
for i := 0;i < 4; i++ {
fmt.Print(arr1[i])
c <- 1 // 开启宁一个协程
<-d // 阻塞本协程
}
wg.Done()
}()
go func() {
for i := 0;i < 4 {
<-c // 阻塞本协程
fmt.Print(arr2[i])
d <- 1 // 开启宁一个协程
}
wg.Done()
}()
wg.Wait() // 阻塞主协程
fmt.Println()
fmt.Println("hello world!")
}
channel阻塞
环形缓存区概念,对缓存区满时会存在一个sudog类型的链表里,该链表记录哪个协程在等待哪个channel以及等待发送数据等。 环形缓存区保证了:当channel缓冲区满时不会立刻堵塞,数据会临时存入到sudog里面,当该channel中数据在被接收时,sudog的数据会立刻填回去,充当了一个临时存储作用。 阻塞时机:
- channel为nil
- channel没有缓存区或缓存区用尽,也没有协程等着接收数据。
- 给返回值放到宁外一个独立的goroutine里面
- 加锁or原子操作存储到外层变量
[1] (28条消息) Golang常见面试题及解答_golang 面试_西木Qi的博客-CSDN博客 [2] (28条消息) Golang 面试总结_golang gmp调度面试_CHAO9172的博客-CSDN博客 [3] (28条消息) GoLang之channel数据结构及阻塞、非阻塞操作、多路select_channel非阻塞_~庞贝的博客-CSDN博客