C 事件驱动IO和阻塞与非阻塞

C 事件驱动IO和阻塞与非阻塞,c,optimization,io,blocking,nonblocking,C,Optimization,Io,Blocking,Nonblocking,有人能给我解释一下事件驱动IO系统调用(如select、poll和epoll)与阻塞IO和非阻塞IO之间的关系吗 我不明白它们之间有多大的关联性——如果有的话,这些概念在很大程度上是不相关的,只是出于以下原因,您可能希望将非阻塞文件描述符与事件驱动IO结合使用: 旧版本的Linux在内核中肯定有bug,即使select指示套接字是可读的,读也会被阻塞。UDP套接字和校验和错误的数据包也会发生这种情况。当前版本的Linux可能仍然有一些这样的bug;我不确定 如果其他进程有可能访问您的文件描述符并

有人能给我解释一下事件驱动IO系统调用(如select、poll和epoll)与阻塞IO和非阻塞IO之间的关系吗


我不明白它们之间有多大的关联性——如果有的话,这些概念在很大程度上是不相关的,只是出于以下原因,您可能希望将非阻塞文件描述符与事件驱动IO结合使用:

旧版本的Linux在内核中肯定有bug,即使select指示套接字是可读的,读也会被阻塞。UDP套接字和校验和错误的数据包也会发生这种情况。当前版本的Linux可能仍然有一些这样的bug;我不确定

如果其他进程有可能访问您的文件描述符并将对其进行读/写,或者如果您的程序是多线程的,而其他线程可能会这样做,则select确定文件描述符可读/写与您的程序对其执行IO之间存在争用条件,这可能导致阻塞

在调用connect之前,您几乎肯定希望使套接字不阻塞;否则,您将阻塞,直到建立连接。使用“选择写入”确定连接成功的时间,并选择“错误”确定连接是否失败

几乎所有unix都支持select系统调用,它为userland应用程序提供了监视一组描述符并获取关于该组中哪个子集已准备好读/写的信息的方法。它特殊的接口有点笨重,大多数内核的实现充其量只是平庸

epoll仅在Linux中提供用于相同目的,但在效率和编程接口方面比select有了巨大的改进。其他unix也有专门的呼叫

也就是说,事件驱动的IO系统调用不需要阻塞描述符或非阻塞描述符。阻塞是一种影响系统调用(如读、写、接受和连接)的行为。select和epoll_wait确实有阻塞超时,但这与描述符无关

当然,使用这些带有阻塞描述符的事件驱动系统调用有点奇怪,因为您希望在收到可用数据的通知后,可以立即读取数据而不阻塞。始终依赖于阻塞描述符在您收到准备就绪通知后不会阻塞是有点危险的,因为可能存在争用条件

非阻塞、事件驱动的IO可以大大提高服务器应用程序的效率,因为每个描述符连接都不需要线程。将Apache web服务器与Nginx或Lighttpd在性能方面进行比较,您将看到其好处。

您提到的select和类似功能通常用于在事件驱动系统中实现事件循环

也就是说,应用程序调用多个文件描述符上的select,等待其中任何一个描述符上的数据可用,而不是直接从套接字或文件读取数据(如果没有可用数据,则可能会阻塞)

当文件描述符可用时,可以确保数据可用,并且读取操作不会阻塞


这是一种同时处理来自多个源的数据的方法,而无需使用多个线程。

+1,您还可以添加一个著名的侦听TCP套接字竞赛,其中客户端在选择和接受之间放弃连接尝试。我不确定,但我认为它会为每个工作进程中的每个连接生成一个线程或从池中选择一个线程。我认为每个连接服务器的线程几乎可以与事件驱动的线程一样快。Apache缓慢和膨胀的原因不是线程,而是处理每个请求所涉及的巨大开销。pthread_create的开销仅相当于2-3个open调用的开销,当然,如果在连接到达之前已经在accept上阻塞了线程,那么开销就更低了。@R..:那么,上下文切换呢?如果线程与CPU的数量相对应,那么就可以了,但是如果你有数千个线程连接呢?@R:我相信你的基准测试已经执行并讨论过了:@loan:从使用线程(特别是在Linux上)的时代起,该站点就相当老了,完全是一个笑话。被称为LinuxThreads的骇人听闻的黑客仍然是主流。。。