多线程、IO模型、epoll杂谈

1.
面向多核的服务器编程时,多线程并不如多进程,因为对于每个进程来说,资源是独立的,切换core的时候无需考虑上下文;
而多线程中,每个线程共享资源,在core切换的时候,资源必须从一个core复制到另一个core才能继续运算。
换句话说,在cpu多核的情况下,多线程反而不如多进程。


2.
浏览器开一个页面,页面中很多图片,下载每个图片开一个线程;
迅雷下载的时候是把文件分片,多线程下载,最后合到一个主线程中;如果一个线程下载缓慢,主线程可以停掉它并开启另外一个线程;
浏览器没打开一个标签,就是一个进程,这点可以在chrome上做实验。


3.
select通过轮询来处理fd,轮询的fd越多,自然耗时越多;


4.五种io模型
(1)阻塞式
(2)非阻塞式
(3)io多路复用
select/poll: 将一个或多个fd(fd_set)传给select/poll系统调用,阻塞在select,select/poll通过轮询来查找fd是否就绪,如果就绪,则返回;
epoll: epoll是基于事件驱动方式,不是轮询,当有fd准备就绪时,立刻回调callback。
(4)信号驱动
典型的是sigaction绑定一个信号处理函数(sigaction系统调用立即返回,进程继续执行,非阻塞式的,直到接到信号),接到信号后进行处理;
(5)异步io
信号驱动io在通知后启动io;而异步io是开始就启动,得到信号通知后开始执行??


5.io多路复用详解
(1)select最不能容忍的是对打开的fd有个数限制,默认2048,对于支持上万连接的服务器来说太少,处理的方法是或者修改FD_SETSIZE的宏值,或者采用多进程方案(传统apach方案),虽然linux上创建进程代价远小于windows,但仍旧不可忽视,加上进程同步不如线程同步高效,所以并不完美。
epoll没有这个限制,它支持fd的上限是最大可打开文件的数目。
(2)io效率不随socket集合的增加而下降,因为select是轮询机制,要扫描所有的fd;epoll是事件驱动机制,只有活跃的socket才会用到,内核上的实现是根据每个fd的callback函数实现的;
在一个高速lan环境中,epoll并不比select/poll有效率;而在一个idle connection的模拟wlan环境中,epoll效率就高多了。
(3)epoll的底层实现使用mmap加速内核与用户空间的消息传递;


实现:
epool本身占用一个fd,所以最后需要关闭打开的epoll描述符;
int epoll_create(int size);
int close(int fd);
int epoll_ctl(...) //添加监听事件
int epoll_wait(...) //阻塞监听函数,类似于select
epoll的工作方式有level triggered和edge triggered,LT是默认的,fd准备好后,内核持续通知,直到被操作;而ET只通知一次。


那么,epoll是如何实现可以高效处理百万句柄的?(http://blog.csdn.net/russell_tao/article/details/7160071)
(1)epoll在被内核初始化时(epoll_create),会开辟出epoll自己的内核高速cache区,用于安置每一个我们想要监听的socket,将它们用红黑树的形式保存在cache中,以支持快速的增删改查。并且还会建立一个list,用于存储准备就绪的事件。
(2)当我们向epoll_ctl中塞入百万句柄的时候,除了把一个socket放到红黑树上以外,还会给该socket在内核中断处理程序注册一个callback函数,告诉内核,如果这个句柄的中断到了,就直接把socket数据从网卡copy到list里;
(3)每次调用epoll_wait时(非阻塞),直接返回list里的数据,所以非常高效。



这里有一个epoll实现的demo:

http://blog.csdn.net/xiaonamylove/article/details/4252563


6.redis持久化
RDB snapshot
AOF append only file
http://www.cnblogs.com/zhoujinyi/archive/2013/05/26/3098508.html

你可能感兴趣的:(多线程、IO模型、epoll杂谈)