为了账号安全,请及时绑定邮箱和手机立即绑定

做异步I/O时,内核如何判断一个I/O操作是否完成?

做异步I/O时,内核如何判断一个I/O操作是否完成?

Go
白衣染霜花 2022-01-04 10:07:36
关于为什么我问这个的一些背景。几个小时前我问过这个问题哪个有答案所有的 I/O 都必须通过系统调用来完成,并且在 Go 中实现系统调用的方式,它们总是通过由运行时控制的代码来调用。这意味着当您调用系统调用时,而不是直接调用它(从而将线程的控制权交给内核),运行时会收到您想要进行的系统调用的通知,并代表 goroutine 执行此操作。例如,这允许它执行非阻塞系统调用而不是阻塞系统调用(本质上是告诉内核,“请执行此操作,但不要阻塞直到完成,立即返回,并在结果后通知我准备好了”)。这允许它同时继续做其他工作。所以根据我的理解,golang 调度器的作用是确保不会在等待 I/O 操作的线程上花费时间。相反,它以某种方式将这个责任推给了内核。但是,我想更深入地了解这个过程,因为我有很多不清楚的地方。现在这是我的理解,这可能是完全错误的。向 goroutine 中的远程服务器发出 I/O 请求,例如 GET 请求Golang 进行系统调用以读取 TCP 流,这是一个阻塞操作,但它不会等待,而是要求内核在获得信息时得到通知。调度器从它的队列中移除阻塞的 goroutine当内核获得所有信息时,它会将其转发给 go 进程,并让调度程序知道将 goroutine 添加回其队列。我正在努力理解的是如何在不创建另一个线程的情况下完成 I/O 操作,以及内核如何实际“知道”完成 I/O 操作。是通过轮询还是有某种中断系统?我希望这有点道理。我对这种低级别的概念很陌生。
查看完整描述

1 回答

?
Helenr

TA贡献1780条经验 获得超4个赞

下面的 KERNEL 表示“内核端”。它包括操作系统内核代码 + 加载的驱动程序。

鉴于您有一个到远程服务器的 TCP 连接。这是内核如何处理异步写入/读取 TCP 流的示例。

当您将字节数组发送到 TCP 流时,内核会将缓冲区流放入 RAM 并控制 DMA 系统将缓冲区复制到网卡。当 DMA 完成其工作时,会调用 CPU 内部的中断。内核注册的中断处理程序会将来自 DMA 的信号转换为用于写入 TCP 流方法的完成回调。当然,实际的 TCP 堆栈要复杂得多。这些句子只是关于事情如何运作的想法。

对于从 TCP 流读取的情况,当一个包进入网卡时,会调用另一个中断。内核注册的另一个处理程序会将中断转换为 golang 端的事件。

同样,实际情况非常非常复杂。操作系统很多,版本很多,IO操作的种类很多,硬件设备也很多。


查看完整回答
反对 回复 2022-01-04
  • 1 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号