asyncio异步携程模块python
在python3.4以后新增了asyncio模块,能够帮咱们检测IO(只能是网络IO【HTTP链接就是网络IO操做】),实现应用程序级别的切换(异步IO)。注意:asyncio只能发tcp级别的请求,不能发http协议。 flask
- 异步IO:所谓「异步 IO」,就是你发起一个 网络IO 操做,却不用等它结束,你能够继续作其余事情,当它结束时,你会获得通知。 - 实现方式:单线程+协程实现异步IO操做。 - 异步协程用法 协程的实现,从 Python 3.4 开始,Python 中加入了协程的概念,但这个版本的协程仍是以生成器对象为基础的,在 Python 3.5 则增长了 async/await,使得协程的实现更加方便。首先须要了解下面几个概念: event_loop:事件循环,至关于一个无限循环,咱们能够把一些函数注册到这个事件循环上,当知足条件发生的时候,就会调用对应的处理方法。 coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,咱们能够将协程对象注册到时间循环中,它会被事件循环调用。咱们可使用 async 关键字来定义一个方法,这个方法在调用时不会当即被执行,而是返回一个协程对象。 task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。 future:表明未来执行或没有执行的任务的结果,实际上和 task 没有本质区别。 从 Python 3.5 出现的async/await 关键字,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。
aiohttp异步网络请求模块服务器
aiohttp
是基于asyncio
实现的HTTP框架,pip install aiohttp。 网络
1 import aiohttp 2 3 #简单的基本架构: 4 async def request(url): 5 async with aiohttp.ClientSession() as s: 6 #s.get/post和requests中的get/post用法几乎同样:url,headers,data/prames 7 #在s.get中若是使用代理操做:proxy="http://ip:port" 8 async with await s.get(url) as response: 9 #获取字符串形式的响应数据:response.text() 10 #获取byte类型的:response.read() 11 page_text = await response.text() 12 return page_text
单线程+多任务异步协程架构
协程:协程对象。使用async关键字修饰一个函数的定义(特殊的函数),当该特殊的函数被调用后,就能够返回一个协程对象。当函数调用后,函数内部的实现语句不会被当即执行。协程就是一个用async关键字修饰的特殊函数。协程定义:async def func():pass,建立协程对象:c=func() app
1 ''' 2 协程是一个用async关键字修饰的特殊函数; 3 在这个特殊函数内不容许出现不支持异步模块的代码,不然异步非阻塞将失效; 4 在特殊函数中遇到阻塞的代码前必须使用await关键字手动挂起(后续示例) 5 6 ''' 7 #定义一个协程 8 async def func(): 9 print('一个协程对象') 10 11 #建立协程对象 12 c=func()
任务对象:本质上就是对协程对象进一步封装,比如是一个特殊函数。任务对象task=asyncio.ensure_future(c)能够绑定一个回调函数:task.add_done_callback(func_callback)-----func_callback回调函数只能接受task任务对象执行结果返回值,类比进程池/线程池中submit提交任务后的回调函数使用! 框架
1 ''' 2 任务对象是对协程对象进行封装后的一个特殊函数; 3 任务对象能够绑定一个回调函数; 4 ''' 5 import asyncio 6 #定义一个协程 7 async def func(n): 8 print(n) 9 10 #定义任务对象的回调函数:只能接受以个参数,该参数为任务对象执行结果返回值 11 def call_back(task): 12 print(task.result()) 13 14 #建立协程对象 15 c=func(-1) 16 17 18 #建立任务对象 19 task=asyncio.ensure_future(c) 20 #任务对象绑定回调函数 21 task.add_done_callback(call_back) 22 23 # 建立多个任务对象并为其绑定回调函数 24 task_list=[] 25 for i in range(5): 26 c=func(i) 27 task=asyncio.ensure_future(c) 28 task.add_done_callback(task) 29 task_list.append(task)
事件循环:事件循环对象的建立loop=asyncio.get_event_loop()。必须将任务对象注册到事件循环对象中,自动开启事件循环对象,在执行任务对象的时候是基于异步的。单个任务对象的注册:loop.run_until_complete(task);多个任务对象的注册:loop.run_and_complete(asyncio.wait(task_list))。 异步
1 ''' 2 建立事件循环对象对任务对象进行注册调用; 3 注册单个任务对象/注册多个任务对象并自动调用执行; 4 5 ''' 6 import asyncio 7 #定义一个协程 8 import time 9 10 11 async def func(n): 12 await asyncio.sleep(2)#必须使用支持异步模块的代码,同时在遇到阻塞的代码前必须使用await手动挂起 13 print(n) 14 return n 15 16 #定义任务对象的回调函数:只能接受以个参数,该参数为任务对象执行结果返回值 17 def call_back(task): 18 print(task.result()) 19 20 #建立协程对象 21 c=func(-1) 22 23 start=time.time() 24 #建立任务对象 25 task0=asyncio.ensure_future(c) 26 #任务对象绑定回调函数 27 task0.add_done_callback(call_back) 28 29 # 建立多个任务对象并为其绑定回调函数 30 task_list=[] 31 for i in range(5): 32 c=func(i) 33 task=asyncio.ensure_future(c) 34 task.add_done_callback(call_back) 35 task_list.append(task) 36 37 #建立事件循环对象 38 loop=asyncio.get_event_loop() 39 #注册单个任务对象 40 loop.run_until_complete(task0) 41 #注册多个任务对象 42 loop.run_until_complete(asyncio.wait(task_list)) 43 44 loop.close() 45 print(time.time()-start)#2.00264573097229
注意事项:async
单线程多任务异步爬虫实例tcp
flask服务器脚本构建:
import time from flask import Flask app=Flask(__name__) @app.route('/<id>') def func1(id): time.sleep(2) return id if __name__ == '__main__': app.run()
单线程多任务异步数据采集代码:
1 import time 2 import asyncio # pip install asyncio 3 import aiohttp #pip install aiohttp 4 headers = { 5 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36' 6 } 7 #建立urls列表 8 urls = [] 9 for i in range(500): 10 urls.append(f'http://127.0.0.1:5000/{i}') 11 12 #定义携程函数-----简单的基本架构 13 async def request(url): 14 async with aiohttp.ClientSession() as s: 15 #s.get/post和requests中的get/post用法几乎同样:url,headers,data/prames 16 #在s.get中若是使用代理操做:proxy="http://ip:port" 17 async with await s.get(url) as response: 18 #获取字符串形式的响应数据:response.text() 19 #获取byte类型的:response.read() 20 page_text = await response.text() 21 return page_text 22 23 #定义任务对象回调函数 24 def parse(task): 25 page_text = task.result() 26 print(f'响应结果:{page_text}') 27 28 29 #建立任务列表 30 start = time.time() 31 tasks = [] 32 for url in urls: 33 c = request(url) 34 task = asyncio.ensure_future(c) 35 task.add_done_callback(parse) 36 tasks.append(task) 37 #建立事件循环对象并将任务对象列表进行注册 38 loop = asyncio.get_event_loop() 39 loop.run_until_complete(asyncio.wait(tasks)) 40 loop.close() 41 print(time.time()-start)#3.4196295738220215