Fil*_*lly 74 asynchronous epoll io-completion-ports
可能有人解释的区别是什么之间epoll,poll和线程池?
epoll和poll有特定的Linux ...是否有适用于Windows的等量替代?Dam*_*mon 211
Threadpool并不真正适合与poll和epoll相同的类别,因此我假设您将"线程池"称为"线程池以处理每个连接一个线程的多个连接".
epoll,虽然显而易见的方式(所有线程阻塞epoll_wait)没有用,因为epoll会唤醒每个等待它的线程,所以它仍然会有相同的问题.
futex是你的朋友,结合每个线程的快进队列.虽然记录严密且难以处理,但仍能futex提供所需的信息.epoll可以一次返回多个事件,并且futex允许您有效且以精确控制的方式一次唤醒N个被阻塞的线程(min(num_cpu, num_events)理想情况下为N ),并且在最好的情况下,它根本不涉及额外的系统调用/上下文切换.fork (又名旧时尚线程)
fork上也不是"免费"的,尽管开销主要是由写时复制机制合并而来.在同样被修改的大型数据集上,大量的页面错误fork可能会对性能产生负面影响.poll/select
epoll
epoll_ctl)
epoll_wait)
poll运作timerfd和eventfd(令人惊叹的计时器分辨率和准确性).signalfd,消除了对信号的笨拙处理,使它们以非常优雅的方式成为正常控制流程的一部分.eventfd,但需要(迄今为止)未记录的功能.poll可能表现相同或更好.epoll不能做"魔术",即就发生的事件数量而言,它仍然必然是O(N).epoll可以很好地处理新的recvmmsg系统调用,因为它一次返回几个就绪通知(尽可能多,直到你指定的任何一个maxevents).这样就可以在繁忙的服务器上通过一个系统调用接收例如15个EPOLLIN通知,并使用第二个系统调用读取相应的15个消息(系统调用减少93%!).不幸的是,一个recvmmsginvokation 上的所有操作都引用相同的套接字,因此它对于基于UDP的服务非常有用(对于TCP,必须有一种recvmmsmsg系统调用,每个项目也需要一个套接字描述符!).EAGAIN即使在使用时epoll也应检查,因为存在epoll报告准备就绪和后续读取(或写入)仍将阻塞的异常情况.这也是的情况下poll/ select上有些内核(尽管它可能被固定).EAGAIN收到通知后返回时,可以无限期地从快速发送者读取新的传入数据,同时完全饿死慢速发送者(只要数据保持足够快,你可能不会看到EAGAIN相当长的一段时间! ).适用于poll/ select以相同的方式.epoll_wait(或自描述符打开以来,如果之前没有调用),IO活动是否已发生.epoll_wait,这表明IO活动已经发生,因为任何人最后呼吁无论是 epoll_wait 或在描述一个读/写功能,并且此后只有一次报告的准备调用或已被阻塞的下一个线程 epoll_wait,用于任何人在描述符上调用读取(或写入)函数之后发生的任何操作.它也有意义......它只是文档所暗示的并不完全正确.kqueue
epoll,不同用法,类似效果.libevent - 2.0版本还支持Windows下的完成端口.
ASIO - 如果您在项目中使用Boost,请不要再看了:您已经将它作为boost-asio提供.
上面列出的框架附带了大量文档.Linux 文档和MSDN广泛地解释了epoll和完成端口.
使用epoll的迷你教程:
int my_epoll = epoll_create(0); // argument is ignored nowadays
epoll_event e;
e.fd = some_socket_fd; // this can in fact be anything you like
epoll_ctl(my_epoll, EPOLL_CTL_ADD, some_socket_fd, &e);
...
epoll_event evt[10]; // or whatever number
for(...)
if((num = epoll_wait(my_epoll, evt, 10, -1)) > 0)
do_something();
Run Code Online (Sandbox Code Playgroud)
IO完成端口的小型教程(注意使用不同的参数调用CreateIoCompletionPort两次):
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); // equals epoll_create
CreateIoCompletionPort(mySocketHandle, iocp, 0, 0); // equals epoll_ctl(EPOLL_CTL_ADD)
OVERLAPPED o;
for(...)
if(GetQueuedCompletionStatus(iocp, &number_bytes, &key, &o, INFINITE)) // equals epoll_wait()
do_something();
Run Code Online (Sandbox Code Playgroud)
(这些迷你版省略了所有类型的错误检查,希望我没有做任何错别字,但他们应该在很大程度上可以给你一些想法.)
编辑:
请注意,完成端口(Windows)在概念上以epoll(或kqueue)的方式工作.正如他们的名字所示,他们发出完成信号,而不是准备状态.也就是说,你发起一个异步请求并忘记它,直到一段时间后你被告知它已经完成(成功也没有那么成功,并且还有"立即完成"的例外情况).
使用epoll,您将阻止,直到通知您"某些数据"(可能只有一个字节)已到达且可用或有足够的缓冲区空间,因此您可以在不阻塞的情况下执行写入操作.只有这样,你才开始实际的操作,然后希望不会阻塞(除了你的预期,没有严格的保证 - 因此最好将描述符设置为非阻塞并检查EAGAIN [EAGAIN 和 EWOULDBLOCK]对于套接字,因为哦快乐,标准允许两个不同的错误值]).