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. ...
随机推荐
- 使用 Xbox Game 录制桌面视频(录制音频)
使用 Xbox Game 录制桌面视频(附带音频) 前言:可能自己音频输出的问题,一直无法用工具录制桌面的音频,而最后发现利用 Xbox Game 录制游戏视频的功能很好地解决我们的问题. 1)打开游 ...
- Kafka学习笔记之Kafka High Availability(下)
0x00 摘要 本文在上篇文章基础上,更加深入讲解了Kafka的HA机制,主要阐述了HA相关各种场景,如Broker failover,Controller failover,Topic创建/删除,B ...
- ASP.NET Core appsettings.json 文件
ASP.NET Core appsettings.json 文件 在本节中,我们将讨论 ASP.NET Core 项目中appsettings.json文件的重要性. 在以前的 ASP.NET 版本中 ...
- Java开发设计——七大原则
Java开发设计——七大原则 摘要:本文主要介绍了在做面向对象开发时要注意的七个原则. 部分内容来自以下博客: https://www.cnblogs.com/xiyuekamisama/p/1057 ...
- HighChat动态绑定数据 数据后台绑定(四)
后台绑定数据,直接返回json数据 IList<SummaryHour> adHourData = summarybll.FindList(str); List<, , , , , ...
- 开发技术--浅谈python数据类型
开发|浅谈python数据类型 在回顾Python基础的时候,遇到最大的问题就是内容很多,而我的目的是回顾自己之前学习的内容,进行相应的总结,所以我就不玩基础了,很多在我实际生活中使用的东西,我会在文 ...
- webpack加载css文件及其配置
webpack加载css文件及其配置 当我们写了几个css文件之后如果想要引用到html中去的话我们最开始的方式就是通过link标签将css文件导入进去,但是如果我们的css文件有很多的话,一个个的导 ...
- Android Activity之间的数据传递
1.向目标Activity传递数据: Intent intent=new Intent(this,Main2Activity.class); //可传递多种类型的数据 intent.putExtra( ...
- [Go] golang的MPG调度模型
MPG模式运行状态11)当前程序有三个M,如果三个M都在一个cpu运行,就是并发,如果在不同的cpu运行就是并行2)M1,M2,M3正在执行一个G,M1的协程队列有三个,M2的协程队列有三个,M3的协 ...
- 常用的linux命令大全
之前做过两年的运维,用过很多命令,深切体会到某些linux命令熟练掌握后对效率提升有多大.举个简单的例子,在做了研发后经常会有跑一些数据,对于结果数据的处理,我们的产品同学一般都习惯于用excel做统 ...