python 利用selectors实现异步I/O
它的功能与linux的epoll,还是select模块,poll等类似;实现高效的I/O multiplexing, 常用于非阻塞的socket的编程中; 简单介绍一下这个模块,更多内容查看 python文档:https://docs.python.org/3/library/selectors.html
1. 模块定义了一个 BaseSelector的抽象基类, 以及它的子类,包括:SelectSelector, PollSelector, EpollSelector, DevpollSelector, KqueueSelector.
另外还有一个DefaultSelector类,它其实是以上其中一个子类的别名而已,它自动选择为当前环境中最有效的Selector,所以平时用 DefaultSelector类就可以了,其它用不着。
2. 模块定义了两个常量,用于描述 event Mask
EVENT_READ : 表示可读的; 它的值其实是1;
EVENT_WRITE: 表示可写的; 它的值其实是2;
3. 模块定义了一个 SelectorKey类, 一般用这个类的实例 来描述一个已经注册的文件对象的状态, 这个类的几个属性常用到:
fileobj: 表示已经注册的文件对象;
fd: 表示文件对象的描述符,是一个整数,它是文件对象的 fileno()方法的返回值;
events: 表示注册一个文件对象时,我们等待的events, 即上面的event Mask, 是可读呢还是可写呢!!
data: 表示注册一个文件对象是邦定的data;
4. 最后说说抽象基类中的方法;
| register(fileobj, events, data=None) |
作用:注册一个文件对象。 参数: fileobj——即可以是fd 也可以是一个拥有fileno()方法的对象; events——上面的event Mask 常量; data 返回值: 一个SelectorKey类的实例; |
| unregister(fileobj) |
作用: 注销一个已经注册过的文件对象; 返回值:一个SelectorKey类的实例; |
| modify(fileobj, events, data=None) |
作用:用于修改一个注册过的文件对象,比如从监听可读变为监听可写;它其实就是register() 后再跟unregister(), 但是使用 modify( ) 更高效; 返回值:一个SelectorKey类的实例; |
| select(timeout=None) |
作用: 用于选择满足我们监听的event的文件对象; 返回值: 是一个(key, events)的元组, 其中key是一个SelectorKey类的实例, 而events 就是 event Mask(EVENT_READ或EVENT_WRITE,或者二者的组合) |
| close() |
作用:关闭 selector。 最后一定要记得调用它, 要确保所有的资源被释放; |
| get_key(fileobj) |
作用: 返回注册文件对象的 key; 返回值 :一个SelectorKey类的实例; |
服务端
#!/usr/bin/env python
# -*- coding: utf- -*-
from socket import *
import selectors sel=selectors.DefaultSelector() def accept(server_fileobj,mask):
coon,addr = server_fileobj.accept()
print(coon,addr,mask)
sel.register(coon,selectors.EVENT_READ,read) def read(conn,mask):
try:
data = conn.recv()
if not data:
print('closing',conn)
sel.unregister(conn)
conn.close()
return
conn.send(b'hello')
except Exception:
print('closing', conn)
sel.unregister(conn)
conn.close() server_fileobj = socket(AF_INET,SOCK_STREAM)
server_fileobj.setsockopt(SOL_SOCKET,SO_REUSEADDR,)
server_fileobj.bind(('127.0.0.1',))
server_fileobj.listen()
server_fileobj.setblocking(False)#设置socket的接口为非阻塞 #相当于往select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept
sel.register(server_fileobj,selectors.EVENT_READ,accept) while True:
#检测所有的fileobj,是否有完成wait data的
events = sel.select()
# SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
for sel_obj,mask in events:
callable = sel_obj.data
callable(sel_obj.fileobj,mask)
客户端
#!/usr/bin/env python
# -*- coding: utf- -*-
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',)) while True:
msg=input('>>: ')
if not msg:continue
c.send(msg.encode('utf-8'))
data=c.recv()
print(data.decode('utf-8'))
模拟请求
#. epoll并不代表一定比select好
# 在并发高的情况下,连接活跃度不是很高, epoll比select
# 并发性不高,同时连接很活跃, select比epoll好 #通过非阻塞io实现http请求
# select + 回调 + 事件循环
# 并发性高
# 使用单线程 import socket
from urllib.parse import urlparse
from selectors import DefaultSelector, EVENT_READ, EVENT_WRITE selector = DefaultSelector()
#使用select完成http请求
urls = []
stop = False class Fetcher:
def connected(self, key):
selector.unregister(key.fd)
self.client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(self.path, self.host).encode("utf8"))
selector.register(self.client.fileno(), EVENT_READ, self.readable) def readable(self, key):
d = self.client.recv()
if d:
self.data += d
else:
selector.unregister(key.fd)
data = self.data.decode("utf8")
html_data = data.split("\r\n\r\n")[]
print(html_data)
self.client.close()
urls.remove(self.spider_url)
if not urls:
global stop
stop = True def get_url(self, url):
self.spider_url = url
url = urlparse(url)
self.host = url.netloc
self.path = url.path
self.data = b""
if self.path == "":
self.path = "/" # 建立socket连接
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.setblocking(False) try:
self.client.connect((self.host, )) # 阻塞不会消耗cpu
except BlockingIOError as e:
pass #注册
selector.register(self.client.fileno(), EVENT_WRITE, self.connected) #心脏, 心脏在不停的跳动,跳动就会知道调用什么代码,执行什么方法
#不停的向操作系统询问哪些socket已经准备好了,然后执行回调方法
def loop():
#事件循环,不停的请求socket的状态并调用对应的回调函数
#. select本身是不支持register模式
#. socket状态变化以后的回调是由程序员完成的
while not stop:
ready = selector.select()
for key, mask in ready:
call_back = key.data
call_back(key)
#回调+事件循环+select(poll\epoll) if __name__ == "__main__":
fetcher = Fetcher()
import time
start_time = time.time()
for url in range():
url = "http://shop.projectsedu.com/goods/{}/".format(url)
urls.append(url)
fetcher = Fetcher()
fetcher.get_url(url)
loop()
print(time.time()-start_time)
python 利用selectors实现异步I/O的更多相关文章
- Python之路,Day10 - 异步IO\数据库\队列\缓存
Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...
- Day10 - Python协程、异步IO、redis缓存、rabbitMQ队列
Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...
- 利用aiohttp制作异步爬虫
asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块.关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述一个基于asyncio实现的HTTP框架--a ...
- [Python] 利用Django进行Web开发系列(二)
1 编写第一个静态页面——Hello world页面 在上一篇博客<[Python] 利用Django进行Web开发系列(一)>中,我们创建了自己的目录mysite. Step1:创建视图 ...
- python利用or在列表解析中调用多个函数.py
python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...
- Java利用httpasyncclient进行异步HTTP请求
Java利用httpasyncclient进行异步HTTP请求 前段时间有个需求在springmvc mapping的url跳转前完成一个统计的业务.显然需要进行异步的处理,不然出错或者异常会影响到后 ...
- python 利用 ogr 写入shp文件,数据格式
python 利用 ogr 写入 shp 文件, 定义shp文件中的属性字段(field)的数据格式为: OFTInteger # 整型 OFTIntegerList # 整型list OFTReal ...
- Python利用pandas处理Excel数据的应用
Python利用pandas处理Excel数据的应用 最近迷上了高效处理数据的pandas,其实这个是用来做数据分析的,如果你是做大数据分析和测试的,那么这个是非常的有用的!!但是其实我们平时在做 ...
- python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)
python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie) 主要包括两部分内容:(1)利用python中的dict实现Trie:(2) ...
随机推荐
- 3、jeecg 笔记之 模糊查询
1.前言 jeecg 考虑到默认模糊查询的话,会增加系统压力,导致查询慢,本来系统就挺那啥的... 2.方式一之实体赋值 实体重新赋值查询,用 * %% * 实现,我们知道 sql 中通常使用 % 去 ...
- 编程实现类似Linux系统的cp功能
选做题目以及分析 题目:编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文 ...
- C++的默认构造函数
待看文章:C++ 合成默认构造函数的真相 默认构造函数指不带参数或者所有参数都有缺省值的构造函数!!! 类的默认构造函数可以使得在实例化该类的对象时不用提供参数,但是类也可以不含默认构造函数,这样在实 ...
- 在服务器上搭建node环境
一般公司的发布是后台人员完成的,但是作为开发不会发布项目还是有点不高级的感觉 因为没有搭建虚拟机于是就直接在我阿里云的服务器上搭建了node环境, 第一步,前往node官网下载linux下的阿里云的镜 ...
- GDscript风格指南
(惯例感谢godot开发组~~·) 缩进 缩进类型:Tabs (编辑器默认) 缩进大小:4 (编辑器默认) 每个缩进级别必须大于包含它的代码块. 良好的: for i in range(10): pr ...
- 14 python读取文件时出现UnicodeDecodeError: 'gbk' codec can't decode byte 0xb7 in position 26: illegal multibyte sequence解决方法
>>> f = open("D:\\all.txt", "r")>>> f.read()Traceback (most re ...
- [转载]资深程序员点评当前某些对Lotus Domino 的不实评论
实现机关办公自动化工作需要计算机技术的支持,在计算机软件范围中,有网络操作系统软件.数据库软件和开发工具等基本系统软件,在此基础上开发出适合本单位使用的应用软件.对如何选用系统软件,笔者没有发言权,但 ...
- Missing library: xdoclet-1.2.1.jar.如何解决?
去这里下载xdoclet-bin-1.2.1.zip http://sourceforge.net/projects/xdoclet/files/xdoclet/1.2.1/ 解压出来,比如解压到C: ...
- 数据库oracle 目录结构
Oracle_Home主目录位于D:\dev\oracle\product\10.2.0(oracle安装路径)下,它包含Oracle软件运行有关的子目录和网络文件以及选定的组件等:若在主机上第一次且 ...
- js BOM浏览器对象模型
BOM即Browser Object Model,浏览器对象模型,表示浏览器窗口,所有js全局对象.函数以及变量均是window 对象的成员. 对于不同的浏览器,表示宽度和高度的方法不同: 对于IE9 ...