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

关于为什么我问这个的一些背景。几个小时前我问过这个问题

哪个有答案

所有的 I/O 都必须通过系统调用来完成,并且在 Go 中实现系统调用的方式,它们总是通过由运行时控制的代码来调用。这意味着当您调用系统调用时,而不是直接调用它(从而将线程的控制权交给内核),运行时会收到您想要进行的系统调用的通知,并代表 goroutine 执行此操作。例如,这允许它执行非阻塞系统调用而不是阻塞系统调用(本质上是告诉内核,“请执行此操作,但不要阻塞直到完成,立即返回,并在结果后通知我准备好了”)。这允许它同时继续做其他工作。


所以根据我的理解,golang 调度器的作用是确保不会在等待 I/O 操作的线程上花费时间。相反,它以某种方式将这个责任推给了内核。

但是,我想更深入地了解这个过程,因为我有很多不清楚的地方。

现在这是我的理解,这可能是完全错误的。

  1. 向 goroutine 中的远程服务器发出 I/O 请求,例如 GET 请求

  2. Golang 进行系统调用以读取 TCP 流,这是一个阻塞操作,但它不会等待,而是要求内核在获得信息时得到通知。调度器从它的队列中移除阻塞的 goroutine

  3. 当内核获得所有信息时,它会将其转发给 go 进程,并让调度程序知道将 goroutine 添加回其队列。

我正在努力理解的是如何在不创建另一个线程的情况下完成 I/O 操作,以及内核如何实际“知道”完成 I/O 操作。是通过轮询还是有某种中断系统?

我希望这有点道理。我对这种低级别的概念很陌生。


白衣染霜花
浏览 194回答 1
1回答

Helenr

下面的 KERNEL 表示“内核端”。它包括操作系统内核代码 + 加载的驱动程序。鉴于您有一个到远程服务器的 TCP 连接。这是内核如何处理异步写入/读取 TCP 流的示例。当您将字节数组发送到 TCP 流时,内核会将缓冲区流放入 RAM 并控制 DMA 系统将缓冲区复制到网卡。当 DMA 完成其工作时,会调用 CPU 内部的中断。内核注册的中断处理程序会将来自 DMA 的信号转换为用于写入 TCP 流方法的完成回调。当然,实际的 TCP 堆栈要复杂得多。这些句子只是关于事情如何运作的想法。对于从 TCP 流读取的情况,当一个包进入网卡时,会调用另一个中断。内核注册的另一个处理程序会将中断转换为 golang 端的事件。同样,实际情况非常非常复杂。操作系统很多,版本很多,IO操作的种类很多,硬件设备也很多。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go