理解libuv/epoll/非阻塞网络IO

5
我正在尝试理解在Node.js/libuv中非阻塞网络IO是如何工作的。我已经发现文件IO是使用libuv工作线程完成的(因此在后台线程中)。然而,各种地方都指出,网络IO是使用诸如epoll、kqueue等系统调用以非阻塞方式完成的(取决于操作系统)。
现在我想知道这是否意味着实际的IO部分(read())仍然在主线程上进行,因此是阻塞的,即使使用了epoll等。就我所知,epoll只是通知可用事件,但并不实际执行读/写。至少在我找到的示例中(例如http://davmac.org/davpage/linux/async-io.html),epoll总是与阻塞IO操作的read系统调用结合使用。
换句话说,如果libuv正在使用单个线程和epoll,那么当数据可读时,接下来的读取操作是否在主线程上执行,从而可能阻塞主线程上的其他操作(考虑网络请求)?

实际上,epoll 有两种模式,通常我们使用的是只在数据到达时触发用户一次的模式,因此我们需要将套接字设置为非阻塞模式。 - Stargateur
非阻塞模式下的套接字意味着当没有数据可用时,read系统调用不会被阻塞。因此,实际的IO操作仍然在后台进行吗? - user826955
epoll/poll/select 都是用于在 fd 准备好进行操作时进行 IO 操作而不会阻塞的。使用 poll/epoll/select,您可以在单个线程上执行异步操作,并进行阻塞操作。 - Tyker
@user826955 "所以实际的IO仍然没有在后台完成?" 你是什么意思?读取就是实际的IO。 - Stargateur
1
@user826955,世界上没有真正的异步系统。一切都是同步的。但是你可以将同步系统转换为“看起来像”异步的东西。这是许多库的目的。你的问题太广泛了。实现异步的一种方法是使用epoll,另一种方法是使用线程。 - Stargateur
显示剩余3条评论
1个回答

3

文件描述符是指向文件的引用,无论如何,epoll/poll/select总是报告这些文件已准备好读/写,然而,read/write可能会阻塞等待数据被读取/写入。因此,文件I/O必须在单独的线程中完成。

而使用管道和套接字进行非阻塞的send/recv是真正的非阻塞,因此可以在I/O线程中完成而不会阻塞该线程。


这是否意味着在调用recv时,可用数据已经被某个东西(操作系统?)传输/缓冲了? - user826955
@user826955 是的,数据确实在内核套接字缓冲区中,需要被复制到进程地址空间,这就是非阻塞recv所做的。 - Maxim Egorushkin
但是将内容复制到进程地址空间基本上与将文件内容从文件IO复制到进程内存相同,对吧?换句话说,它使用资源/CPU时间,并且不会立即/原子地完成。 我真的只是想了解异步网络IO与libuv中的异步文件IO有何区别,因为根据他们的文档,只有文件IO使用专用后台线程进行IO工作。 - user826955
1
@user826955 不,文件数据存储在其他地方,而套接字数据已经被内核接收。 - Maxim Egorushkin

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