select、poll、epoll
select、poll、epoll都是IO多路复用的机制,其中epoll是Linux特有的。本质上都是同步IO,有设备就绪或超时才能执行后面的动作
select与poll:
本质上没有区别,时间复杂度都是O(n);实现上都需要不断轮询从用户空间拷贝过来的文件句柄fd的数组,看是否有设备准备就绪,这样监测fd越多,开销越大。
但poll机制监测的文件句柄数没有限制,不同于select(一般监测数量1024,可以通过cat /proc/sys/fs/file_max查看),poll是基于链表存储的。
epoll:
时间复杂度为O(1),不同于select与epoll,epoll使用mmap文件映射,开辟一块共享空间,用于内核空间与用户空间的消息传递,效率上要高。
epoll有两种触发方式:EPOLLLT(默认)与EPOLLET(边缘触发)。
epoll最大的优点在于它只管理“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率远高于select和poll。
异步IO与多线程:
linux中关于异步IO的实现有两种:
1、基于glibc的多线程实现,并不是正真的异步IO,比如aio_read、aio_write等会通过系统调用到file_operatios中的aio_read和aio_write;
2、linux内核中的异步IO
int io_setup(unsigned nr_events, aio_context_t *ctxp);
功能:用来初始化异步IO的上下文。
其中参数ctxp用来描述异步IO上下文, 参数nr_events表示小可处理的异步IO事件的个数。
int io_submit(io_context_t ctx, long nr, struct iocb *iocbs[]);
功能:提交初始化好的异步读写事件。
其中ctx是上文的描述句柄, nr表示提交的异步事件个数。Iocbs是异步事件的结构体。
int io_getevents(io_context_t ctx, long nr, struct io_event *events[], struct timespec *timeout);
功能:获得已经完成的异步IO事件。
其中参数ctx是上下文的句柄,nr 表示期望获得异步IO事件个数,events用来存放已经完成的异步事件的数据,timeout为超时事件。
int io_destroy(aio_context_t ctx);
功能:用于销毁异步IO事件句柄。