什么是协程
OS 并不理解 协程,协程是在 userspace
模拟出来的调度,协程运行在线程之上,所以协程没有上下文切换消耗。
Go什么时候会阻塞调用线程?
太长不看版:
Go 进行系统调用时,如果 OS 对于 socket,file 的 文件描述符fd 不支持 IO multiplxing,Go 会阻塞调用线程。
我们都知道,goroutine
是在线程上模拟调度出来的,那在什么情况下,go runtime 会再创建新的线程?
我们从最基础的概念开始。
进程的系统调用是以线程为单位的,而 goroutine 是在线程之上,user space
模拟出的调度。当 Go code 进行系统调用时,code
当前运行的线程会进行 syscall
,从而使得调用线程被阻塞。操作系统不理解 goroutine
,只能感知到 线程,所以可以理解为,当进行系统调用时,线程就是 Go
押在操作系统的人质(不押韵)
对于 socket
的读写操作都属于系统调用。
设想一下这个场景,我们开发了一个 http server, 每个连接都使用新的 goroutine
去处理,那当我们有 1000 个 connections
,线程数应到 1000+(并且大部分都阻塞),但这不合实际。实际上,Go 对于 socket
实现了高效了 IO多路复用。
将 blocking thread
转换为 blocking goroutine
的设计叫做 netpoller
netpoller
从 goroutine
接受事件,然后将其分发到操作系统提供的IO处理器。
在 Linux
中使用 epoll
,BSD, Drawin
下使用 kqueue
,Windows
下使用 IOCP
https://morsmachine.dk/netpoller
但 netpoll
是为 socket
,那对于普通的文件呢?
再次设想一下:
我们对磁盘中 10000
个文件进行读写,如果不使用 poll
技术,我们需要阻塞至少 10000
个线程,这简直无法接受。
这个问题在 Github Issues
上有很多的讨论。
你可以在最后的参考中找到链接
为什么 Go 只为 socket
使用 poll
技术呢?
Windows 下的 IOCP 支持 socket, file
Linux 下的 epoll
只支持 socket
所以 正是由于不同平台对于 poll
技术支持特性的不同,使得 Go 在读写文件时会采用阻塞线程的无奈之举。
直到反应的人越来越多,Go
最终在 这个PR 中完善了处理
那如何解决的呢?
我们用读取文件举例子。
windows
下 ReadFile
实现 runtime/syscall_windows.go
1 | func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) { |
1 | This function(ReadFile) is designed for both synchronous and asynchronous operations. |
现在 Go
统一对 socket,file
的 文件描述符 fd
做了异步处理。
在 Linux
下,由于 epoll
不支持 对于文件的读写,所以 Go
像之前那样阻塞调用线程。
如果 goroutine
进行了阻塞式系统调用,那么当前线程会被阻塞,当 go
调度器没有足够的线程可以支持其余的 goroutine
时,调度器会创建额外的线程
runtime.LockOSThread 是做什么呢?
还是到了 goroutine
与 thread
的区别。
操作系统并不理解协程,协程是在 userspace
中模拟调度出来的。
既然 OS
不理解协程,Go
进行系统调用时,必须以线程为质押。
go scheduler
并不保证 goroutine
始终在同一线程运行。所以为了确保系统调用能够成功,进行 syscall
的 goroutine(A)
必须固定在某个线程运行,调用 LockOSThread
之后,其余的 goroutine
不能在这个线程运行。除非 A
调用 UnlockOSThread
参考来源:
- https://github.com/golang/go/commit/c05b06a12d005f50e4776095a60d6bd9c2c91fac
- https://github.com/golang/go/issues/18507
- https://github.com/golang/go/issues/6222
- https://github.com/golang/go/issues/6817
- https://stackoverflow.com/questions/8057892/epoll-on-regular-files
- https://morsmachine.dk/netpoller