【问题标题】:When doing asynchronous I/O, how does the kernel determine if an I/O operation is completed?做异步I/O时,内核如何判断一个I/O操作是否完成?
【发布时间】:2016-07-29 05:09:47
【问题描述】:

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

When a goroutine blocks on I/O how does the scheduler identify that it has stopped blocking?

有答案

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


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

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

目前这是我的理解,可能完全错误。

  1. 向 go​​routine 中的远程服务器发出 I/O 请求,例如 GET 请求
  2. Golang 进行系统调用以读取 TCP 流,这是一个阻塞操作,但它不是等待,而是要求内核在获得信息时得到通知。调度器从它的队列中移除那个阻塞的 goroutine
  3. 内核获得所有信息后,会将其转发给 go 进程,并让调度程序知道将 goroutine 添加回其队列。

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

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

【问题讨论】:

    标签: multithreading asynchronous go io kernel


    【解决方案1】:

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

    假设您与远程服务器建立了 TCP 连接。这是一个内核如何处理异步写入/读取 TCP 流的示例。

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

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

    同样,真实案例非常复杂。操作系统多,版本多,IO操作种类多,硬件设备多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-14
      • 1970-01-01
      • 2017-06-22
      • 2016-04-14
      • 2012-09-14
      • 2013-06-19
      相关资源
      最近更新 更多