Python Select 解析

首先列一下,sellect、poll、epoll三者的区别 
select 
select最先于1983年出如今4.2BSD中,它经过一个select()系统调用来监视多个文件描述符的数组(在linux中一切事物皆文件,块设备,socket链接等。),当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位(变成ready),使得进程能够得到这些文件描述符从而进行后续的读写操做(select会不断监视网络接口的某个目录下有多少文件描述符变成ready状态【在网络接口中,过来一个链接就会创建一个'文件'】,变成ready状态后,select就能够操做这个文件描述符了)。linux

【socketserver是经过多线程来处理多个请求,每一个链接过来分配一个线程来处理,可是select是单进程的,一个进程执行代码确定就是串行的,可是如今就要经过一个进程来实现并发的效果,一个进程下只有一个主线程,也就说说用一个线程实现并发的效果。为何要用一个进程实现多并发而不采用多线程实现多并发呢?==========答:由于一个进程实现多并发比多线程是实现多并发的效率还要高,由于启动多线程会有不少的开销,并且CPU要不断的检查每一个线程的状态,肯定哪一个线程是否能够执行。这个对系统来讲也是有压力的,用单进程的话就能够避免这种开销和给系统带来的压力,那么单进程是如何实现多并发的呢???========答:很巧妙的使用了生产者和消费者的模式(异步),生产者和消费者能够实现非阻塞,一个socketserver经过select接收多个链接过来(以前的socket一个进程只能接收一个链接,当接收新的链接的时候产生阻塞,由于这个socket进程要先和客户端进行通讯,两者是彼此互相等待的【客户端发一条消息,服务端收到,客户端等着返回....服务端等着接收.........】一直在阻塞着,这个时候若是再来一个链接,要等以前的那个链接断了,这个才能够连进来。-----------也就是说用基本的socket实现多进程是阻塞的。为了解决这个问题采用每来一个链接产生一个线程,是不阻塞了,可是当线程数量过多的时候,对于cpu来讲开销和压力是比较大的。)对于单个socket来讲,阻塞的时候大部分的时候都是在等待IO操做(网络操做也属于IO操做)。为了不这种状况,就出现了异步=============客户端发起一个链接,会在服务端注册一个文件句柄,服务端会不断轮询这些文件句柄的列表,主进程和客户端创建链接而没有启动线程,这个时候主进程和客户端进行交互,其余的客户端是没法链接主进程的,为了实现主进程既能和已链接的客户端收发消息,又能和新的客户端创建链接,就把轮询变的很是快(死循环)去刷客户端链接进来的文件句柄的列表,只要客户端发消息了,服务端读取了消息以后,有另外一个列表去接收给客户端返回的消息,也不断的去刷这个列表,刷出来后返回给客户端,这样和客户端的此次通讯就完成了,可是跟客户端的链接尚未断,可是就进入了下一次的轮询。。。。。。。。。。。】数组

 

 

 

 

 

select目前几乎在全部的平台上支持,其良好跨平台支持也是它的一个优势,事实上从如今看来,这也是它所剩很少的优势之一。网络

select的一个缺点在于单个进程可以监视的文件描述符的数量存在最大限制,在Linux上通常为1024,不过能够经过修改宏定义甚至从新编译内核的方式提高这一限制。数据结构

另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增加。同时,因为网络响应时间的延迟 使得大量TCP链接处于非活跃状态,但调用select()会对全部socket进行一次线性扫描,因此这也浪费了必定的开销。多线程

poll 
poll在1986年诞生于System V Release 3,它和select在本质上没有多大差异,可是poll没有最大文件描述符数量的限制。并发

poll和select一样存在一个缺点就是,包含大量文件描述符的数组被总体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增长而线性增大。异步

另外,select()和poll()将就绪的文件描述符告诉进程后,若是进程没有对其进行IO操做,那么下次调用select()和poll() 的时候将再次报告这些文件描述符,因此它们通常不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。socket

epoll 
直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具有了以前所说的一切优势,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。性能

epoll能够同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,若是咱们没有采起行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,可是代码实现至关复杂。线程

epoll一样只告知那些就绪的文件描述符,并且当咱们调用epoll_wait()得到就绪文件描述符时,返回的不是实际的描述符,而是一个表明 就绪描述符数量的值,你只须要去epoll指定的一个数组中依次取得相应数量的文件描述符便可,这里也使用了内存映射(mmap)技术,这样便完全省掉了 这些文件描述符在系统调用时复制的开销。

另外一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用必定的方法后,内核才对全部监视的文件描 述符进行扫描,而epoll事先经过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用相似callback的回调 机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便获得通知。

相关文章
相关标签/搜索