自定义IO异步基础知识:

--所有的请求都基于socket实现,一个请求就是一个socket

socket.setblocking(False) 不需要阻塞,一个请求完了发送另外一个,会报错,需解决

--IO多路复用[是同步的请求]

IO多路复用有epoll, poll, select,知道epoll性能比其他几者要好[epoll先找到门牌号然后找人]。

IO多路复用本质上是在同一个线程或进程中,通过拨动开关的方式来执行多个IO操作。注意实际上每个IO操作都是独立进行的。只是由原来的一对一变成了多对多。

r,w,e = select.select([],[],[], 超时时间)  # socket有请求/响应前面的r,w,e都会接收到的

IO异步原理:

      IO异步的实现:本质则是【非阻塞Socket】+【IO多路复用】

IO异步的实现:本质则是【非阻塞Socket】+【IO多路复用】

import select
import socket
import time class AsyncTimeoutException(TimeoutError):
"""
请求超时异常类
"""
def __init__(self, msg):
self.msg = msg
super(AsyncTimeoutException, self).__init__(msg) # 封装了socket和buffer的对象
class HttpContext(object):
"""封装请求和相应的基本数据"""
def __init__(self, sock, host, port, method, url, data, callback, timeout=5):
"""
sock: 请求的客户端socket对象
host: 请求的主机名
port: 请求的端口
port: 请求的端口
method: 请求方式
url: 请求的URL
data: 请求时请求体中的数据
callback: 请求完成后的回调函数
timeout: 请求的超时时间
"""
self.sock = sock
self.callback = callback
self.host = host
self.port = port
self.method = method
self.url = url
self.data = data
self.timeout = timeout
self.__start_time = time.time()
self.__buffer = [] def is_timeout(self):
"""当前请求是否已经超时"""
current_time = time.time()
if (self.__start_time + self.timeout) < current_time:
return True def fileno(self):
"""请求sockect对象的文件描述符,用于select监听"""
return self.sock.fileno() def write(self, data):
"""在buffer中写入响应内容"""
self.__buffer.append(data) def finish(self, exc=None):
"""在buffer中写入响应内容完成,执行请求的回调函数"""
if not exc:
response = b''.join(self.__buffer)
self.callback(self, response, exc)
else:
self.callback(self, None, exc) def send_request_data(self):
content = """%s %s HTTP/1.0\r\nHost: %s\r\n\r\n%s""" % (
self.method.upper(), self.url, self.host, self.data,)
return content.encode(encoding='utf8') class AsyncRequest(object):
def __init__(self):
self.fds = []
self.connections = [] def add_request(self, host, port, method, url, data, callback, timeout):
"""创建一个要请求"""
client = socket.socket()
client.setblocking(False) # 不阻塞请求,不等待回应
try:
client.connect((host, port))
except BlockingIOError as e:
pass
# print('已经向远程发送连接的请求')
req = HttpContext(client, host, port, method, url, data, callback, timeout)
self.connections.append(req) # 封装HttpContext对象
self.fds.append(req) def check_conn_timeout(self):
"""检查所有的请求,是否有已经连接超时,如果有则终止"""
timeout_list = []
for context in self.connections:
if context.is_timeout():
timeout_list.append(context)
for context in timeout_list:
context.finish(AsyncTimeoutException('请求超时'))
self.fds.remove(context)
self.connections.remove(context) def running(self):
"""事件循环,用于检测请求的socket是否已经就绪,从而执行相关操作"""
while True:
r, w, e = select.select(self.fds, self.connections, self.fds, 0.05)
if not self.fds:
return for context in r:
sock = context.sock
while True:
try:
data = sock.recv(8096)
if not data:
self.fds.remove(context)
context.finish()
break
else:
context.write(data)
except BlockingIOError as e:
break
except TimeoutError as e:
self.fds.remove(context)
self.connections.remove(context)
context.finish(e)
break for context in w:
# 已经连接成功远程服务器,开始向远程发送请求数据
if context in self.fds:
data = context.send_request_data()
context.sock.sendall(data)
self.connections.remove(context) self.check_conn_timeout() if __name__ == '__main__':
def callback_func(context, response, ex):
"""
:param context: HttpContext对象,内部封装了请求相关信息
:param response: 请求响应内容
:param ex: 是否出现异常(如果有异常则值为异常对象;否则值为None)
:return:
"""
print(context, response, ex) obj = AsyncRequest()
# 基于TCP构造HTTP
url_list = [
{'host': 'www.google.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5,
'callback': callback_func},
{'host': 'www.baidu.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5, 'callback': callback_func},
{'host': 'www.bing.com', 'port': 80, 'method': 'GET', 'url': '/', 'data': '', 'timeout': 5, 'callback': callback_func},
]
for item in url_list:
print(item)
obj.add_request(**item)
obj.running()

Python学习---IO的异步[自定义异步IO]的更多相关文章

  1. python 学习笔记12(事件驱动、IO多路复用、异步IO)

    阻塞IO和非阻塞IO.同步IO和异步IO的区别 讨论背景:Linux环境下的network IO. 1.先决条件(几个重要概念) 1.1.用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32 ...

  2. Python学习-day10(番外篇) 阻塞IO 非阻塞IO 同步IO 异步IO

    这个章节的内容是关于IO的概念,谈一谈什么是 阻塞IO 非阻塞IO 同步IO 异步IO.以下摘要是我对这四种IO的一个形象理解. 场景是去去银行办理业务.节点有三个,1)到银行提交申请:2)取号:3) ...

  3. python学习之路-第八天-文件IO、储存器模块

    文件IO.储存器模块 文件IO 代码示例: # -*- coding:utf-8 -*- #! /usr/bin/python # filename:using_file.py poem = '''\ ...

  4. 【Python学习之九】asyncio—异步IO

    asyncio 这是python3.4引入的标准库,直接内置对异步IO的支持.asyncio的编程模型就是一个消息循环.从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程 ...

  5. python 学习笔记九 队列,异步IO

    queue (队列) 队列是为线程安全使用的. 1.先入先出 import queue #测试定义类传入队列 class Foo(object): def __init__(self,n): self ...

  6. python学习笔记之四-多进程&多线程&异步非阻塞

    ProcessPoolExecutor对multiprocessing进行了高级抽象,暴露出简单的统一接口. 异步非阻塞 爬虫 对于异步IO请求的本质则是[非阻塞Socket]+[IO多路复用]: & ...

  7. python学习之算法、自定义模块、系统标准模块(上)

    算法.自定义模块.系统标准模块(time .datetime .random .OS .sys .hashlib .json和pickle) 一:算法回顾: 冒泡算法,也叫冒泡排序,其特点如下: 1. ...

  8. python学习笔记:模块——自定义模块的3种导入方式

    一.定义 模块就是用一堆的代码实现了一些功能的代码的集合,通常一个或者多个函数写在一个.py文件里,而如果有些功能实现起来很复杂,那么就需要创建n个.py文件,这n个.py文件的集合就是模块.如果不懂 ...

  9. Python学习---django多对多自定义第三方表180206

    案例一: # version: python3.2.5 # author: 'FTL1012' # time: 2018/2/6 16:25 from django.db import models ...

随机推荐

  1. WPF的ControlTemplate和DataTemplate简介

    首先理清几个概念,Template.ControlTemplate.ContentTemplate.DataTemplate.ContentControl 这几个东西名字都差不多,意思感觉也接近,初次 ...

  2. 配置jenkins slave 问题,ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.

    因为需要需要搭建一套自动化环境的windows电脑作为slave,简单的把原来用来mac上的job配置一模一样的配置了下,运行时遇到如上问题,google半天百思不得其解, 后来尝试把SCM里面的br ...

  3. SpringMVC 之 Hello World 入门

    1 准备开发环境和运行环境 依赖 jar 包下载,如下图所示: 2 前端控制器的配置 在我们的web.xml中添加如下配置: <!-- The front controller of this ...

  4. Asterist搭建步骤

    环境: # cat /proc/version Linux version 2.6.18-308.el5 (mockbuild@x86-010.build.bos.redhat.com) (gcc v ...

  5. 概述Java集合框架

    JAVA集合框架主要分为三个部分:接口,实现和算法.接口是指以Collection和Map为起始的一系列公用接口,其中还有Vector接口,也就是迭代器,Collection接口下面又有List 和S ...

  6. java网络编程(UDP详解)

    UDP详解 一,TCP/IP协议栈中,TCP协议和UDP协议的联系和区别? 联系: TCP和UDP是TCP/IP协议栈中传输层的两个协议,它们使用网络层功能把数据包发送到目的地,从而为应用层提供网络服 ...

  7. drupal7 带表达式条件的update

    原本的mysql语句是这样的: ; 转化成drupal的api是这样的 $total_amount=1; $rows= db_update('my_payment_card') ->expres ...

  8. css对ie的兼容性问题处理(一):

    1.在制作sidebar时对li里面的元素进行浮动,li在ie6/7下会出现4px的间间隙: 解决方法:在li下加上vertical-align属性,值可为top.bottom.middle: 扩展: ...

  9. 文档类型、DOCTYPE切换和浏览器模式

    DTD(文档类型定义)是一种机器可读的规则,它们定义XML或HTML的特定版本中允许有什么.不允许有什么.在解析网页时,浏览器将使用这些规则检查页面的有效性并且采取相应的措施.浏览器通过分析页面的DO ...

  10. VC++ 共享内存读写操作

    此解决方案含两个工程文件,一个是写操作工程文件,即把任意字符串写入创建的共享内存里,另外一个读操作工程文件,则是读取共享内存里的数据,从而实现了进程之间的共享内存读写操作. 源码下载