众所周知,goroutine 是同步但非阻塞的处理单元。golang 调度器很好地处理了非阻塞任务,例如套接字、定时器、信号或来自字符设备的其他事件。但是块设备 io 或 CPU 敏感任务呢?它们在完成之前不能被中断,也不能被多路复用。运行 goroutine 的 OS 线程将冻结,直到 goroutine 返回或让步。在这种情况下,调度粒度变差。当然,你可以在你的代码中将任务拆分成更小的子任务,例如,不要一次复制 1GB 的文件,而是先复制 10MB,然后再复制 10MB 等,以便其他 goroutine 在相同的操作系统线程有机会运行。CPU 密集型任务的另一个示例:部分压缩文件并最终合并它们。但这破坏了顺序编程的便利性,与OS线程上的OS调度相比,手动调度难以均匀估计。nginx 也有类似的问题,它是多进程程序,一个 CPU 核一个进程,类似于 GOMAXPROCS 的最佳实践。它引入线程池来处理阻塞任务。也许它对 golang 也有好处。我很好奇为什么golang没有OS线程API,这对于阻塞任务的goroutine应该是很好的补充。
1 回答
临摹微笑
TA贡献1982条经验 获得超2个赞
Go 特别选择不直接向用户公开 OS 线程,而是选择了 M:N 线程模型。Go 中的执行单元是 goroutine,它将在 N 个操作系统线程上多路复用。
在极少数情况下,您的 CPU 密集型计算不包含抢占点且操作系统线程不足以继续运行其他 goroutine,您有 2 个选择;增加 GOMAXPROCS,或插入runtime.Gosched()
调用以屈服于其他 goroutine。
在阻塞系统调用的情况下,Go 调度器会自动调度一个新的 OS 线程(考虑一个系统调用“阻塞”的时间限制为 20us),并且由于非网络 IO 是一系列阻塞系统调用,它几乎总是分配给专用的操作系统线程。由于 Go 已经使用了 M:N 线程模型,用户通常不知道底层调度程序的选择,并且可以像运行时使用异步 IO 一样编写程序。
考虑使用异步文件 IO有一个悬而未决的问题,但有许多问题需要克服,例如 Linux aio api 中的缺点、跨平台兼容性以及与可以执行 IO 的所有各种文件系统和设备的交互。
- 1 回答
- 0 关注
- 319 浏览
添加回答
举报
0/150
提交
取消