【Golang】高性能编程之超时退出协程
2021/12/14 17:18:11
本文主要是介绍【Golang】高性能编程之超时退出协程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
- 超时控制在网络编程中是非常常见的,利用
context.WithTimeout
和time.After
都能够很轻易地实现。
func doBadthing(done chan bool) { time.Sleep(time.Second) done <- true } func timeout(f func(chan bool)) error { done := make(chan bool) go f(done) select { case <-done: fmt.Println("done") return nil case <-time.After(time.Millisecond): return fmt.Errorf("timeout") } } // timeout(doBadthing)
对于这段代码,会出现超时,子协程是不能够全部正常退出的。参见如何退出协程 goroutine 超时场景
- 它的问题是,它使用的是无缓冲的channel,当select执行到超时,doBadthing发送给done的信息没有接收方,因为进到了超时分支,所以,发送方doBadthing会一直阻塞,导致协程不能退出。
那如果在实际的业务中,我们使用了上述的代码,那越来越多的协程会残留在程序中,最终会导致内存耗尽(每个协程约占 2K 空间),程序崩溃。 - 如何避免呢?
1.创建有缓冲区的channel,使得即使没有接收方,发送方也不会发生阻塞。
2.使用select尝试发送
func doGoodthing(done chan bool) { time.Sleep(time.Second) select { case done <- true: default: return } }
如果发送失败则,会直接退出。
3.拆分任务,分为多段,配合select使用,判断哪一段超时。
- 强制Kill goroutine
goroutine 只能自己退出,而不能被其他 goroutine 强制关闭或杀死。
goroutine 被设计为不可以从外部无条件地结束掉,只能通过 channel 来与它通信。也就是说,每一个 goroutine 都需要承担自己退出的责任。(A goroutine cannot be programmatically killed. It can only commit a cooperative suicide.)
- 建议
因为 goroutine 不能被强制 kill,在超时或其他类似的场景下,为了 goroutine 尽可能正常退出,建议如下:
1.尽量使用非阻塞 I/O(非阻塞 I/O 常用来实现高性能的网络库),阻塞 I/O 很可能导致 goroutine 在某个调用一直等待,而无法正确结束。
2.业务逻辑总是考虑退出机制,避免死循环。
3.任务分段执行,超时后即时退出,避免 goroutine 无用的执行过多,浪费资源。
参考
如何退出协程 goroutine 超时场景
这篇关于【Golang】高性能编程之超时退出协程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24MongoDB资料:新手入门完全指南
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享