I/O多路复用-EPOLL探索
I/O多路复用就是通过一种机制,可以监视多个描述符,一旦某个IO能够读写,通知程序进行相应的读写操作。
I/O多路复用的场合
1、当客户处理多个描述字时(通常是交互式输入和网络套接字),必须使用I/O复用
2、如果一个TCP服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
3、如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
Linux 下I/O多路复用的方式
SELECT、POLL、EPOLL
对比SELECT、POLL、EPOLL
SELECT缺点
每次调用select,都需要把fd集合从用户态拷贝到内核态,开销和fd的数量成正比
每次调用select都需要在内核遍历传递进来的所有fd,开销和fd的数量成正比
select支持的文件描述符数量太少,32位1024个,64位2048个
POLL缺点
poll和select本质相同,使用链表存储文件描述符,没有最大连接数的限制
下图是select、poll、kqueue(FreeBSD平台)、epoll四种方式连接数和时间关系图
上图可以看出,随着fd数量的增大,select、poll的时间消耗非常大,kqueue和epoll基本上没有变化
EPOLL优点
1、它所支持的FD上限是最大可以打开文件的数目,在1GB内存的机器上大约是10万左 右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
2、IO 效率不随FD数目增加而线性下降
3、epoll不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd,而不是全部遍历。
下面是一个场景,一个服务端Server.py,多个客户端订阅,服务端不断的生成消息,客户端订阅后服务端会不断的把消息发送给客户端:
Server:
#!/usr/bin/env python
# -*- coding:utf-8 -*- __author__ = 'Andy'
import socket, select, traceback, time
import threading
import Queue gen = Queue.Queue()
connections = {}
requests = {}
responses = {} def run():
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversocket.bind(('127.0.0.1', 8080))
serversocket.listen(5)
serversocket.setblocking(0)
epoll = select.epoll() # 创建一个epoll对象
epoll.register(serversocket.fileno(), select.EPOLLIN) # 给新建的serversocket.fileno注册一个读event try:
count = 0
while True:
events = epoll.poll() # 激活的fileno举手
count += 1
for fileno, event in events:
if fileno == serversocket.fileno(): # 当激活的fileno是新建的,给该fileno注册一个读event
connection, address = serversocket.accept()
connection.setblocking(0)
epoll.register(connection.fileno(), select.EPOLLIN)
connections[connection.fileno()] = connection
requests[connection.fileno()] = b''
responses[connection.fileno()] = b""
print "new conn.fileno is %s" % connection.fileno()
elif event & select.EPOLLIN: # 如果fileno是读event,接收发送来消息,并修改该fileno为写event,下次循环时写数据
print "read event is happing"
requests[fileno] += connections[fileno].recv(1024)
epoll.modify(fileno, select.EPOLLOUT)
print('-' * 40 + '\n' + requests[fileno].decode()[:-2])
elif event & select.EPOLLOUT: # 如果fileno是写事件,写完后正常的为挂起
if responses[fileno]:
byteswritten = connections[fileno].send(responses[fileno])
responses[fileno] = responses[fileno][byteswritten:]
if len(responses[fileno]) == 0:
epoll.modify(fileno, select.EPOLLOUT) # 需要向订阅者一直发消息,这里发完后仍为写event
print "change event to write"
elif event & select.EPOLLHUP:
epoll.unregister(fileno)
connections[fileno].close()
del connections[fileno]
print "event is HUP ===%s" % fileno
pass
except Exception, err:
print traceback.print_exc()
finally:
epoll.unregister(serversocket.fileno())
epoll.close()
serversocket.close()
print "finally" def create_data():
count = 1
while True:
count += 1
res = "Message-%s" % count
gen.put_nowait(res) # 把消息放入队列
time.sleep(0.5) def update_message():
while True:
message = gen.get()
for res in responses: # 遍历所有的活跃用户,更新消息
responses[res] = message
time.sleep(0.05) if __name__ == "__main__":
p = threading.Thread(target=create_data) # 开个线程向队列里放数据
p1 = threading.Thread(target=update_message) # 从队列中取出数据
p.start()
p1.start()
run()
p.join()
p1.join()
Client:
#!/usr/bin/env python
# -*- coding:utf-8 -*- __author__ = 'Andy'
import socket,time
def sim_client(name,i):
connFd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
connFd.connect(("127.0.0.1", 8080))
connFd.send("Process-%s start subscibe\n\n" % name)
while True:
try:
readData = connFd.recv(1024)
if readData:
print "*"*40 + "\n" + readData.decode()
except:
time.sleep(0.2) if __name__=="__main__":
sim_client("progressage",1)
来看一下输出结果
服务端接受订阅的消息:
客户端订阅服务端的消息
才疏学浅,目前只研究了EPOLL的水平触发,还有边缘触发需要去探索
作者:Andy
出处:http://www.cnblogs.com/onepiece-andy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
I/O多路复用-EPOLL探索的更多相关文章
- 非阻塞套接字编程, IO多路复用(epoll)
非阻塞套接字编程: server端 import socket server = socket.socket() server.setblocking(False) server.bind(('', ...
- I/O多路复用——epoll函数
1 select的低效率 select/poll函数效率比较低,主要有以下两个原因: (1)调用select函数后需要对所有文件描述符进行循环查找 (2)每次调用select函数时都需要向该函数传递监 ...
- IO多路复用epoll
0 why: 问题来源 0.1 网络编程流程 //创建socket int s = socket(AF_INET, SOCK_STREAM, 0); //绑定IP地址和端口号port bind(s, ...
- IO多路复用之epoll总结
1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...
- 多路复用(select、epoll)实现tcp服务
-------------------------------多路复用的服务器(select)------------------------------- 网络通信被Unix系统抽象为文件的读写,通 ...
- unix网络编程——I/O多路复用之epoll
1. 基本概念 当程序进行IO时,如果数据尚未准备好,那么IO将处于阻塞状态.当某个进程有多个打开的文件,比如socket,那么其后的所有准备好读写的文件将受到阻塞的影响而不能操作.不借助线程,单一进 ...
- IO多路复用之epoll
1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...
- 【python】-- IO多路复用(select、poll、epoll)介绍及实现
IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...
- IO多路复用(select、poll、epoll)介绍及select、epoll的实现
IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...
随机推荐
- C# 流介绍 (原发布 csdn 2017-09-15 23:37:52)
1.FileStream FileStream 详细介绍参考msdn 写数据: using (FileStream fs = new FileStream("File.FileStream& ...
- 练手WPF(二)——2048游戏的简易实现(下)
接着上一篇继续~~~ 6.动画显示增加分数 /// <summary> /// 动画显示增加得分 /// </summary> /// <param name=" ...
- C#工具类SqlServerHelper,基于System.Data.SqlClient封装
源码: using System; using System.Collections.Generic; using System.Data; using System.Linq; using Syst ...
- CSS覆盖问题的说明
最近在写css的时候,由于经常使用到很长的多级选择器,而碰到一些样式被覆盖或者覆盖不了的情况是相当的郁闷,所以专门花了一些时间对一些选择器做了对比测试.这里先说明一下,由于ie6不支持css2.0选择 ...
- 微信接口调用'updateTimelineShareData','updateAppMessageShareData' 的踩坑记录
6月份新版微信客户端发布后,用户从微信内的网页分享消息给微信好友,以及分享到朋友圈,开发者将无法获知用户是否分享完成.具体调整点为: ()分享接口调用后,不再返回用户是否分享完成事件,即原先的canc ...
- CSS3 transform 属性(2D,3D旋转)
一.语法 div{ transform:rotate(7deg); -ms-transform:rotate(7deg); /* IE 9 */ -moz-transform:rotate(7deg) ...
- Flask补充--threading.local对象
目录 Local 局部变量 全局变量 使用threading.local() 自定义threading.local 函数版 面向对象版 通过setattr和getattr实现 每个对象有自己的存储空间 ...
- global对象,数据存储方式和检测,包装器对象等
1.理解global对象 global对象是作为 window 对象的一部分实现的,我们无法通过代码访问到 global 对象. 我们平时在全局环境下定义的内容(变量,函数,常量等等)都是作为 glo ...
- 使用ES对中文文章进行分词,并进行词频统计排序
前言:首先有这样一个需求,需要统计一篇10000字的文章,需要统计里面哪些词出现的频率比较高,这里面比较重要的是如何对文章中的一段话进行分词,例如“北京是×××的首都”,“北京”,“×××”,“中华” ...
- springcloud学习之路: (二) springcloud打jar包并批量运行
springcloud中内置了tomcat所以打包的时候是直接把tomcat打入jar包 之后就可以做到, 单独的服务, 独立的jar包, 独立运行的效果了. 一.打jar包 1. 在pom.xml文 ...