轮询/poll和epoll会阻塞吗?它们与异步IO有何不同?

5

我一直以为poll/epoll不会阻塞。这就是为什么非阻塞服务器如Nginx使用它们的原因。

但在这个Stackoverflow问题中,有好几次提到poll会阻塞。

那么poll/epoll是否会阻塞?

poll/epoll和异步IO有何不同?


select/poll/epoll均可用于阻塞等待事件的发生。然而,它们不仅可以用于等待单个事件,还可以同时等待多个事件的发生。 - Joey Adams
1个回答

10

是的,poll/epoll会阻塞。将线程用于为客户端提供服务的服务器通常无法像使用I/O事件通知模型(如epoll)的服务器那样具有良好的可扩展性。poll比epoll旧且效率低(O(n) vs O(1))。

[更新]

Nginx不是非阻塞的。当请求到达时,等待epoll_wait之一的事件被通知,并且调用epoll_wait返回。然后,Nginx循环遍历已发出的事件并为每个事件提供服务。Nginx源代码在此处可用... http://nginx.org/download/nginx-1.1.1.tar.gz

查看nginx-1.1.1\src\event\modules\ngx_epoll_module.c中的ngx_epoll_process_events函数

[更新2]

另请参阅epoll_wait(2)的手册页面... http://linux.die.net/man/2/epoll_wait

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

指定超时时间为-1会使epoll_wait(2)无限等待,而指定超时时间为零会使epoll_wait(2)立即返回,即使没有事件可用(返回代码等于零)。 [UPDATE3] 为了证明Nginx / epoll阻塞,请在Linux上尝试以下操作...
  1. 下载源并解压缩
  2. cd到源目录
  3. ./configure --with-debug (注意:我必须添加libpcre3-dev)
  4. make
  5. sudo make install
  6. 启动nginx:/usr/local/nginx/sbin/nginx (注意:我必须先杀死apache sudo /etc/init.d/apache2 stop
  7. sudo gdb
  8. file /usr/local/nginx/sbin/nginx
  9. b ngx_epoll_module.c:531 (设置断点)
  10. 在另一个终端窗口中,ps -ef | grep nginx 并使用nginx工作进程的PID(不是主进程)
  11. 回到gdb中,attach <PID of nginx worker>
  12. continue以恢复进程
您可能需要多次continue,但它最终应该会阻塞。然后打开浏览器并转到http:// localhost …调试器应在epoll_wait返回后立即中断。

1
如果 epoll 阻塞,那么使用 epoll 的服务器(例如 Nginx)如何变成非阻塞状态? - Continuation
谢谢更新。那么,如果Nginx被阻止了,它与像Apache这样的服务器有什么不同呢?此外,epoll的man页面(http://linux.die.net/man/4/epoll)讨论了非阻塞使用:“当使用EPOLLET标志(边缘触发)时,epoll接口应该使用非阻塞文件描述符,以避免阻塞读取或写入使正在处理多个文件描述符的任务饿死。”我错过了什么吗? - Continuation
2
续集:epoll_wait() 本身是一个阻塞接口。每当您调用 epoll_wait(),它都会阻塞您的线程/进程,直到在注册描述符上发生任何受监视事件。手册讲解了 epoll 用于非阻塞 FD 的用法,这就是 epoll 监视的内容,而不是 epoll 本身。换句话说,它说如果您使用 EPOLLET,则应仅在 epoll 上注册非阻塞 FD。无论如何,无论您是否要求 epoll 监视非阻塞或阻塞 FD,epoll 接口本身仍然是基于阻塞的。 - ddoman
2
您可以通过将超时值设置为0,像使用非阻塞接口一样使用epoll_wait()。 - ddoman
@Continuation Apache会处理与新进程/线程的连接,该进程/线程将被阻塞。例如,1000个线程正在等待响应。相比之下,Nginx将使用epoll来注册1000个连接。但是,如果这1000个连接没有任何事情可做,它将被阻塞。当事件发生时,它将继续进行。但是,为了做到这一点,您只需要一个线程,而不是一千个。 - Heurisko

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