// todo 见参考1,2

切片和数组区别:

  • 数组值类型,切片引用类型 数组赋值和传参时,整个数组数据都会赋值一遍,消耗掉大量内存
  • 数组定长,切片长度可变 切片的内部实现是通过指针引用底层数组
golang阻塞

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没有缓存区或缓存区用尽,也没有协程等着接收数据。
golang如何从协程中拿到返回值
  1. 给返回值放到宁外一个独立的goroutine里面
  2. 加锁or原子操作存储到外层变量
参考

[1] (28条消息) Golang常见面试题及解答_golang 面试_西木Qi的博客-CSDN博客 [2] (28条消息) Golang 面试总结_golang gmp调度面试_CHAO9172的博客-CSDN博客 [3] (28条消息) GoLang之channel数据结构及阻塞、非阻塞操作、多路select_channel非阻塞_~庞贝的博客-CSDN博客