关于我为什么这么问的一些背景知识。几个小时前我问过这个问题
When a goroutine blocks on I/O how does the scheduler identify that it has stopped blocking?
有答案
所有I / O必须通过系统调用完成,并且在Go中实现syscalls的方式,它们总是通过运行时控制的代码调用。这意味着当你调用一个系统调用时,而不是直接调用它(从而放弃对内核的线程控制),运行时会收到你想要的系统调用通知,并代表goroutine执行。这允许它,例如,做一个非阻塞的系统调用而不是阻塞系统调用(基本上告诉内核,“请做这件事,但不要阻塞,直到它完成,立即返回,并在结果后让我知道准备好了”)。这允许它在此期间继续做其他工作。
因此,根据我的理解,golang调度程序所做的是确保不会在等待I / O操作的线程上花费时间。相反,它以某种方式将责任推迟到内核。
但是,我希望对这个过程有更深入的了解,因为我有很多不清楚的事情。
现在这是我的理解,这可能是完全错误的。
我正在努力理解的是如何在不创建另一个线程的情况下完成I / O操作,以及内核实际“知道”I / O操作是如何完成的。是通过轮询还是有某种中断系统?
我希望这有点似乎有意义。我对这个低级别的概念很新。
答案 0 :(得分:2)
下面的KERNEL意味着"内核方面"。它包括OS内核代码+加载的驱动程序。
鉴于您与远程服务器建立了TCP连接。以下是Kernel如何处理异步写/读TCP流的示例。
当您将字节数组发送到TCP流时,内核会将缓冲区流放入RAM并控制DMA系统将缓冲区复制到网卡。当DMA完成其工作时,CPU内部会有一个中断被调用。内核注册的中断处理程序将把来自DMA的信号转换为完成回调,以便写入TCP流方法。当然,实际的TCP堆栈要复杂得多。这些句子只是想法是如何运作的。
对于从TCP流读取的情况,当包进入网卡时,会调用另一个中断。内核注册的另一个处理程序会将中断转换为golang端的事件。
同样,真实情况非常复杂。有许多操作系统,许多版本,许多类型的IO操作和许多硬件设备。