这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战
一、uvloop
是asyncio的事件循环的代替方案。事件循环>默认asyncio事件循环。
pip install uvloop
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
# 编写asyncio代码,和之前的一样
async def set_after(fut):
await asyncio.sleep(2)
fut.set_result("666")
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 创建一个任务(Future对象), 这个任务什么都不干。
fut = loop.create_future()
# 创建一个任务(Task对象),绑定set_after函数,函数内部在2s之后,会给fut赋值。
# 即手动设置future任务的最终结果,fut就可以结束。
await loop.create_task(set_after(fut))
# 等待任务最终结果(Future对象),没有结果则会一直等下去。
data = await fut
print(data)
# 内部的事件循环会自动变成uvloop
asyncio.run(main())
运行结果如下:
二、实际应用
1、 异步redis
在使用Python代码操作Redis时,连接/操作/断开都是网络IO。
pip install aioredis
示例1:
import asyncio
import aioredis
async def execute(address, password):
print("开始执行:", address)
# 网络IO操作:创建Redis连接
# 本人Redis没有设置密码,所以连接时不设置password
# redis = await aioredis.create_redis(address, password=password)
redis = await aioredis.create_redis(address)
# 网络IO操作:在Redis中设置hash值car, 内部在设置三个键值对,即:Redis = {car: {key1:1, key2:2, key3:3}}
await redis.hmset_dict('car', key1=1, key2=2, key3=3)
result = await redis.hgetall('car', encoding='utf-8')
print(result)
redis.close()
# 网络操作:关闭Redis
await redis.wait_closed()
print("结束:", address)
asyncio.run(execute('redis://127.0.0.1:6379', ""))
运行结果如下:
示例2:
import asyncio
import aioredis
async def execute(address, password):
print("开始执行:", address)
# 本人Redis没有设置密码,所以连接时不设置password
# redis = await aioredis.create_redis(address, password=password)
# 网络IO操作:先去连接127.0.0.1:6379, 遇到IO则自动切换任务,去连接127.0.0.1:6380
redis = await aioredis.create_redis(address)
# 网络IO操作:遇到IO自动切换任务
await redis.hmset_dict('car', key1=1, key2=2, key3=3)
# 网络IO操作:遇到IO自动切换任务
result = await redis.hgetall('car', encoding='utf-8')
print(result)
redis.close()
# 网络IO操作:遇到IO自动切换任务
await redis.wait_closed()
print("结束:", address)
task_list = [
execute('redis://127.0.0.1:6379', ""),
execute('redis://127.0.0.1:6380', ""),
]
asyncio.run(asyncio.wait(task_list))
运行结果如下:
2、异步MySQL
pip install aiomysql
示例1:
import asyncio
import aiomysql
async def execute():
print("开始执行:")
# 网络IO操作:连接MySQL
conn = await aiomysql.connect(host='127.0.0.1', port=3306, user='root', password='root', db='mysql', )
# 网络IO操作:创建cursor
cur = await conn.cursor()
# 网络IO操作:执行SQL
await cur.execute('select Host, User from user')
# 网络IO操作:获取SQL结果
result = await cur.fetchall()
print(result)
# 网络IO操作:关闭连接
await cur.close()
conn.close()
asyncio.run(execute())
运行结果如下:
示例2:
import asyncio
import aiomysql
async def execute(host, password):
print("开始执行:", host)
# 网络IO操作:先去连接127.0.0.1:3306,遇到IO则自动切换,去连接154.8.147.238:3306
conn = await aiomysql.connect(host=host, port=3306, user='root', password=password, db='mysql', )
# 网络IO操作:遇到IO会自动切换任务
cur = await conn.cursor()
# 网络IO操作:遇到IO会自动切换任务
await cur.execute('select Host, User from user')
# 网络IO操作:遇到IO会自动切换任务
result = await cur.fetchall()
print(result)
# 网络IO操作:遇到IO会自动切换任务
await cur.close()
conn.close()
task_list = [
execute('127.0.0.1', "root"),
execute('154.8.147.238', "root"),
]
asyncio.run(asyncio.wait(task_list))
运行结果如下:
3、FastAPI框架
安装
pip install fastapi
pip install uvicorn (asgi内部基于uvloop)
示例:
import asyncio
import aioredis
import uvicorn
from fastapi import FastAPI
from redis import Redis
app = FastAPI()
# 创建一个Redis连接池
REDIS_POOL = aioredis.ConnectionsPool('redis://127.0.0.1:6379', minsize=1, maxsize=10)
@app.get('/')
def index():
'''普通操作接口'''
return {"message": "hello word"}
@app.get('/red')
async def red():
'''异步操作连接'''
print('请求来了')
await asyncio.sleep(3)
# 连接池获取一个连接
conn = await REDIS_POOL.acquire()
redis = Redis(conn)
# 设置值
await redis.hmset_dict('car', key1=1, key2=2, key3=3)
# 读取值
result = await redis.hgetall('car', encoding='utf-8')
print(result)
# 连接归还连接池
REDIS_POOL.release(conn)
return result
if __name__ == "__main__":
uvicorn.run("luffy:app", host='127.0.0.1', port=5000, log_level='info')
4、爬虫
pip install aiohttp
import aiohttp
import asyncio
async def fetch(session, url):
print("发送请求:", url)
async with session.get(url, verify_ssl=False) as response:
text = await response.text()
print("得到结果:", url, len(text))
return text
async def main():
async with aiohttp.ClientSession() as session:
url_list = [
'https://img.tupianzj.com/uploads/allimg/180704/9-1PF4222401.jpg',
'https://img.tupianzj.com/uploads/allimg/180127/9-1P12G03548.jpg',
'https://img.tupianzj.com/uploads/allimg/190329/34-1Z32Z93602.jpg',
'https://img.tupianzj.com/uploads/allimg/160229/9-160229100600.jpg',
'https://img.tupianzj.com/uploads/allimg/190430/34-1Z4301F923-50.jpg',
'https://img.tupianzj.com/uploads/allimg/202001/9999/fe8c80add1.jpg'
]
tasks = [asyncio.create_task(fetch(session, url) for url in url_list)]
done, pending = await asyncio.wait(tasks)
print(done)
if __name__ == "__main__":
asyncio.run(main())
三、总结
最大的意义:通过一个线程利用其IO等待时间去做一些其他的事情。