非阻塞IO是如何实现的?

18
在Java或C#等某些语言中,有非阻塞IO设施,例如针对套接字。
因此,我可以把我的回调函数给非阻塞IO,一旦非阻塞IO接收到任何内容,它就会调用我的回调函数。
我想知道它们是如何实现的。如果我创建了非阻塞IO,在幕后,Java或C#是否只为它们创建后台线程?还是底层操作系统本身对它们具有本地支持?

请查看此处的备注:http://msdn.microsoft.com/zh-cn/library/dxkwh6zw.aspx。它似乎使用后台线程,如果重新使用相同的上下文,则会被缓存。 - mellamokb
@mellamokb这里说的是执行上下文被缓存和重用,没有涉及到线程的问题。 - Chris Shain
1个回答

19
在Windows操作系统上,存在用于非阻塞I/O的底层OS支持,Microsoft的CLR利用了这一点。其他CLR实现(如Mono)可能也是这样,但我不确定。在Microsoft CLR上执行异步I/O时,挂起的异步I/O操作与等待这些I/O操作完成的线程(或至少是托管线程)之间并不存在一对一的对应关系。
请参见http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx以获取Win32层面的详细信息。此外,在此处查看有关I/O完成端口的信息:http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx 我的理解是:
  1. 我在某个应用程序线程上开始一个异步I/O操作。
  2. 如果尚未创建队列(实际上是与应用程序的内核级构造体关联的内核级构造体,称为I/O完成端口),则将创建队列。在.NET世界中,会启动一个特别指定的线程,称为I/O完成端口线程,以便在该队列上等待I/O完成的通知。重要的是要注意,我可以发出任意数量的异步I/O请求,而不会增加I/O完成端口的数量。
  3. 操作系统将通过将I/O完成消息排队到队列中来通知应用程序I/O已经完成。I/O完成端口线程将通过调用我的.NET应用程序中的I/O完成回调来处理该消息。同时,如果有其他I/O完成,则其结果将排在正在处理的结果后面。
上述存在一些警告:
  1. 我确定我有部分错误,但我相信总体意思是正确的。Eric或其他人可以在我偏离轨道时进行更正。

  • .NET 中有多个 I/O 完成端口线程。我不知道异步 I/O 请求是如何分配到各个 I/O 完成端口的。这可能是一个操作系统特性(其中 I/O 可以回到应用程序打开的任何端口)。

  • 对于 Java,我确定它取决于 JVM 实现和特定的操作系统。我不了解得足够多,无法推测更多。

  • 编辑:历史更新,请参阅 此处 以获取更多详细信息。


  • 你说的 对于C#来说,有底层的操作系统支持... 是什么意思?操作系统并不知道.NET运行在其之上,理论上.NET可以在Windows和Linux上运行(通过mono)。 - Tudor
    请提供更详细的编写内容。 - Jack
    那好的,为您添加了更多细节,杰克。某些地方可能有点偏差,但我认为总体上我的理解是正确的。 - Chris Shain

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接