Skip to content

Commit 30fc115

Browse files
committed
sync content: 2025-12-22 09:07:07
1 parent f066cfa commit 30fc115

1 file changed

Lines changed: 4 additions & 2 deletions

File tree

src/content/posts/技术分享/调度模型/go-schedule.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ top: // 循环起点
460460

461461
### 系统调用
462462

463-
我们经常会说在陷入阻塞系统调用的时候,这个 m 会和 p 立即解绑,会去另外找一个 m 去执行,而非阻塞的系统调用虽然也会解绑,但是这个 m 会记住这个 p,等从系统调用返回之后,会优先去获取这个 p,刘丹冰的《深入理解Go语言》也正是这么写的,但是这个说法并不算准确
463+
我们经常会说在陷入阻塞系统调用的时候,这个 m 会和 p 立即解绑,会去另外找一个 m 去执行,而非阻塞的系统调用虽然也会解绑,但是这个 m 会记住这个 p,等从系统调用返回之后,会优先去获取这个 p,刘丹冰的《深入理解Go语言》也正是这么写的,但是这个说法(阻塞和非阻塞)并不算准确
464464
```go
465465
func reentersyscall(pc, sp, bp uintptr) {
466466
...
@@ -534,9 +534,11 @@ if s == _Psyscall {
534534
```
535535
虽然对于阻塞和非阻塞并没有明确的规定,但是我觉得这里的说法还是可以再优化一下,阻塞还是非阻塞,要不要给这个 P 安排新的 M 完全取决于系统监控以及当时的资源紧张情况。
536536

537+
当然,在退出执行系统调用的时候,会执行 `exitsyscall` 这个函数,此时会优先去获取原来的 p,即陷入系统调用之前记录的 `oldp`,如果这个 p 已经转而去执行其他 m 了,那么就会从空闲的 p 中找一个来执行这个 m,如果没有任何能够执行这个 m 的 p,那么就会将这个 g 放入全局的运行队列,而这个 m 则通过 `stopm` 进入到空闲的 m 列表,并陷入睡眠。
538+
537539
还有一个值得说的是,cgo 调用也会经过 `reentersyscall`,换而言之,系统监控把 cgo 调用也当作系统调用处理。
538540

539-
另外,很多人会认为 `entersyscallblock` 会在调用会引发阻塞的系统调用时调用,实际上并不是这也,前面也说了,`syscall` 包里面只会在进入系统调用之前调用 `reentersyscall`,那么 `entersyscallblock` 到底是干什么的?我们可以注意到调用这个 `entersyscallblock``notetsleepg` 主要是由 `signal_recv` 调用,然后通过 linkname 链接到了 `os/signal` 包,目前来看主要是用于一个信号通知的机制,也就是我们所说的 `Notify` 会用到他,但是这里我也没咋(懒得)研究,有兴趣的可以自己看看吧。
541+
另外,很多人会认为 `entersyscallblock` 会在调用会引发阻塞的系统调用时调用,实际上并不是这样,前面也说了,`syscall` 包里面只会在进入系统调用之前调用 `reentersyscall`,那么 `entersyscallblock` 到底是干什么的?我们可以注意到调用这个 `entersyscallblock``notetsleepg` 主要是由 `signal_recv` 调用,然后通过 linkname 链接到了 `os/signal` 包,目前来看主要是用于一个信号通知的机制,也就是我们所说的 `Notify` 会用到他,但是这里我也没咋(懒得)研究,有兴趣的可以自己看看吧。
540542

541543
### 线程 M
542544

0 commit comments

Comments
 (0)