协成asyncio模块
asyncio即Asynchronous I/O是python一个用来处理并发(concurrent)事件的包,是很多python异步架构的基础,多用于处理高并发网络请求方面的问题。
async:异步
sync:同步
io:input、output输入输出事件
简单来说,asyncio解决的是:IO阻塞导致cpu利用率降低的问题
-------------------------------------------------------------------------------------------------------------------------
为了简化并更好地标识异步,从ython 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读.
asyncio 被用作多个提供高性能 Python 异步框架的基础,包括网络和网站服务,数据库连接库,分布式任务队列等等。
asyncio 往往是构建lo 密集型和高层级 结构化 网络代码的最佳选择。
async与await
● async用于声明一个函数为异步函数,即该函数内部可能会使用到异步操作。
在定义异步函数时,需要在函数定义前加上async关键字。
-------->>>>>
● await用于等待一个异步操作完成。当在一个异步函数中使用await关键字时,该函数会暂停执行,直到等待的异步操作完成并返回结果后,才会继续执行后续代码。
● async.run() :运行协程
=====================================================================
简单示例如下:
import asyncio
import time
async def foo():
print("开始执行foo")
await asyncio.sleep(1) # 模拟异步操作,等待1秒
print("结束执行foo")
async def main():
start = time.time()
print("开始执行main")
await foo() # 等待foo函数执行完毕
print("结束执行main")
print("cost timer:", time.time() - start)
asyncio.run(main()) # 启动主协成
task
task:任务,对协程对象的进一步封装,包含任务的各个状态;
asyncio.Task是Future的一个子类,用于实现协作式多任务的库,且Task对象不能用户手动实例化,通过函数创建,这里重点介绍asyncio.create_task方法:
● async.create_task():创建task
● async.gather() :获取返回值
● asyncio.wait():获取返回值
=====================================================================
以下为3.11版本中,构建协成任务列表的示例:
import asyncio
import time
#主线程
async def foo(i):
print(f"任务{i}启动")
await asyncio.sleep(i) #主线程阻塞
print(f"任务{i}结束")
return i * i #返回每个任务的平方值
#主协成
async def main():
start = time.time()
#显式的创建子协成对象任务,并进行传参
tasks = [asyncio.create_task(foo(1)),
asyncio.create_task(foo(2)),
asyncio.create_task(foo(3))]
await asyncio.wait(tasks) #对协成tasks阻塞的结果收集,得到一个对象
print("cost timer:", time.time() - start) #总耗时
#获取每个任务对象的结果值
for task in tasks:
print(task.done(),task.result())
asyncio.run(main())
上面的栗子中,是等所有协成任务全部结束后,再打印获取每个任务的平方值
如果,我想要在某一个协成任务结束后,就立即获取到该任务的平方值呢?
很简单,只需要使用callback即可,具体代码如下:
import asyncio
import time
#主线程
async def foo(i):
print(f"任务{i}启动")
await asyncio.sleep(i) #主线程阻塞
print(f"任务{i}结束")
return i * i #返回每个任务的平方值
#获取第二个协成对象的返回值
def task2_callback(ret):
print("异步任务2的结果:",ret.result())
#主协成
async def main():
#显式的创建子协成对象任务,并进行传参
tasks = [asyncio.create_task(foo(1)),
asyncio.create_task(foo(2)),
asyncio.create_task(foo(3))]
#获取第二个协成任务之后的回调函数,即平方值
tasks[1].add_done_callback(task2_callback)
res = await asyncio.gather(*tasks) #使用gather直接收集协成对象的结果
print(res)
start = time.time()
asyncio.run(main())
print("cost timer:", time.time() - start) # 总耗时
asyncio.gather
和asyncio.wait
asyncio.gather
和asyncio.wait
都是用于并发执行多个协程(coroutine)的函数但它们之间有一些区别:
参数不同:
asyncio.gather
接收一个协程列表作为参数,并返回一个新的协程。当所有传入的协程都完成时,这个新的协程也会完成。asyncio.wait
接收一个或多个协程以及一个超时时间作为参数。它会阻塞主线程,直到至少有一个协程完成或者超时。返回值不同:
asyncio.gather
返回一个新的协程,可以通过调用其result()
方法获取所有协程的结果。asyncio.wait
返回一个包含已完成协程对象的集合,可以通过遍历这个集合来获取每个协程的结果。异常处理不同:
asyncio.gather
会等待所有传入的协程都完成,如果其中任何一个协程抛出异常,那么整个asyncio.gather
协程都会抛出异常。asyncio.wait
只会等待至少有一个协程完成,如果其中任何一个协程抛出异常,那么asyncio.wait
会立即返回已完成的协程对象集合,而不会继续等待其他协程完成。总结来说,
asyncio.gather
适用于需要等待所有协程都完成的场景,而asyncio.wait
适用于只需要等待至少一个协程完成的场景。
aiohttp包
aiohtpo是一个为Python提供异步HTTP 客户端/服务端编程,基于 asyncio 的异步库。asyncio可以实现单线程并发10操作,其实现了TCP、UDP、SSL等协议,aiohttp就是基于asyncio实现的http框架。
-------->>>>>
我们之前学习过爬虫最重要的模块requests,但它是阻塞式的发起请求,每次请求发起后需阻塞等待其返回响应,不能做其他的事情。
如果需要实现异步爬虫,就不能用requests,可以理解为aiohtpo是requests升级版本。
aiohtpo它是基于 ayncio 的异步模块,可用于实现异步爬虫,优点就是更快于 requests 的同步爬虫。
-------->>>>>
安装方式,pip install aiohttp
一个简单的示例
import aiohttp
import asyncio
async def main():
#异步爬虫session的写