You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
进程的系统调用是以线程为单位的,而 goroutine 是在线程之上,user space 模拟出的调度。当 Go code 进行系统调用时,code 当前运行的线程会进行 syscall,从而使得调用线程被阻塞。操作系统不理解 goroutine,只能感知到 线程,所以可以理解为,当进行系统调用时,线程就是 Go 押在操作系统的人质(不押韵)
什么是协程
OS 并不理解 协程,协程是在
userspace
模拟出来的调度,协程运行在线程之上,所以协程没有上下文切换消耗。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
的设计叫做 netpollernetpoller
从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
Windows下关于 ReadFile API 的文档
现在
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://stackoverflow.com/questions/25361831/benefits-of-runtime-lockosthread-in-golang/25362395#25362395
参考来源:
The text was updated successfully, but these errors were encountered: