Go 语言中让某个协程无限堵塞的几种方式.

Go语言中让某个协程无限堵塞的几种方式.

Go语言自带的goroutine特性会让我们需要在某些时候由 main 函数启动一些协程之后就无限阻塞,让别的协程处理问题.以下是一些方式:

死循环法

1
for {;}

使用这种方式会让你的程序 随机暴毙,无法Debug找到问题出在哪儿.

原因: go语言中的goroutine并不是线程, 当且仅当遇到系统调用和io操作等时候会主动让出自己的时间片等待外部数据.但是,当程序运行死循环的时候 并没有任何io操作,不会主动让出自己的时间片.又由于线程调度的原因,程序会在一个随机时间进入死循环执行,导致整个程序所有协程全部卡死.
Update:新的版本的go语言中提供了抢占式的协程调度,不会出现这个卡死的问题。但是仍然不推荐使用这种方式。为什么要浪费CPU时间呢
不仅如此,由于系统会在别的协程进行io操作的时候进行协程调度,因此 表面上观察到的现象是别的协程在进行io操作的时候堵死整个程序,几乎无法找到bug在哪儿 🌝

死循环让出时间片法

1
2
3
for {
runtime.Gosched()
}

死循环执行 runtime.Gosched() 这一函数,执行这个函数会让出当前协程的时间片,稍后再回到此协程.不会出bug,但是效率偏低. (因为仍然在不断地切换到这个协程.)

死循环Sleep

1
2
3
for {
time.Sleep(Time.Hour)
}

同上,仍然有轻微的(但完全可以忽略)效率问题,但是这样实现十分不优雅.

阻塞的读取空数据法:

1
2
blockChan := make(chan int)
a := <- blockChan

这种方法创建一个不会有数据的Channel,并试图从中读取数据.因为永远读不到数据,因此会堵塞这个协程.

无效率问题,但是实现仍然不优雅.

WaitGroup:

1
2
3
w := sync.WaitGroup{}
wg.Add(1)
wg.Wait()

创建一个WaitGroup,调用 wait 方法无限等待.无效率问题,但是仍然不优雅(要写三行).

Select:

1
select{}

select被用于同步或异步的从Channel中读取数据.因为这里没有指定任何Channel,同时没有default来进行异步读取,程序会阻塞的试图从没有channel中读取数据.

没有创建任何变量, 0内存开销,同时调度器也再也不会调度这个协程,也同样没有性能开销.

(关键是只要一行)