8-3-3python语法基础-并发编程-协程-异步redis,异步MySQL,fastAPI,异步http

实战案例

为了更好理解,上述所有示例的IO情况都是以 asyncio.sleep 为例,而真实的项目开发中会用到很多IO的情况。

异步Redis

当通过python去操作redis时,链接、设置值、获取值 这些都涉及网络IO请求,使用asycio异步的方式可以在IO等待时去做一些其他任务,从而提升性能。

安装Python异步操作redis模块
pip3 install aioredis

示例1:异步操作redis。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import asyncio
import aioredis
async def execute(address, password):
    print("开始执行", address)
    # 网络IO操作:创建redis连接
    redis = await aioredis.create_redis(address, password=password)
    # 网络IO操作:在redis中设置哈希值car,内部在设三个键值对,即: redis = { car:{key1:1,key2:2,key3:3}}
    await redis.hmset_dict('car', key1=1, key2=2, key3=3)
    # 网络IO操作:去redis中获取值
    result = await redis.hgetall('car', encoding='utf-8')
    print(result)
    redis.close()
    # 网络IO操作:关闭redis连接
    await redis.wait_closed()
    print("结束", address)
asyncio.run(execute('redis://47.93.4.198:6379', "root!2345"))
示例2:连接多个redis做操作(遇到IO会切换其他任务,提供了性能)。

import asyncio
import aioredis
async def execute(address, password):
    print("开始执行", address)
    # 网络IO操作:先去连接 47.93.4.197:6379,遇到IO则自动切换任务,去连接47.93.4.198:6379
    redis = await aioredis.create_redis_pool(address, password=password)
    # 网络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://47.93.4.197:6379', "root!2345"),
    execute('redis://47.93.4.198:6379', "root!2345")
]
asyncio.run(asyncio.wait(task_list))
更多redis操作参考aioredis官网:https://aioredis.readthedocs.io/en/v1.3.0/start.html

异步MySQL

当通过python去操作MySQL时,连接、执行SQL、关闭都涉及网络IO请求,
使用asycio异步的方式可以在IO等待时去做一些其他任务,从而提升性能。

安装Python异步操作redis模块

pip3 install aiomysql

示例1:

import asyncio
import aiomysql
async def execute():
    # 网络IO操作:连接MySQL
    conn = await aiomysql.connect(host='127.0.0.1', port=3306, user='root', password='123', 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:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import asyncio
import aiomysql
async def execute(host, password):
    print("开始", host)
    # 网络IO操作:先去连接 47.93.40.197,遇到IO则自动切换任务,去连接47.93.40.198:6379
    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()
    print("结束", host)
task_list = [
    execute('47.93.40.197', "root!2345"),
    execute('47.93.40.197', "root!2345")
]
asyncio.run(asyncio.wait(task_list))

FastAPI框架

FastAPI是一款用于构建API的高性能web框架,框架基于Python3.6+的 type hints搭建。
接下里的异步示例以FastAPI和uvicorn来讲解(uvicorn是一个支持异步的asgi)。
安装FastAPI web 框架,
pip3 install fastapi
安装uvicorn,本质上为web提供socket server的支持的asgi(一般支持异步称asgi、不支持异步称wsgi)
pip3 install uvicorn

示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import asyncio
import uvicorn
import aioredis
from aioredis import Redis
from fastapi import FastAPI
app = FastAPI()
REDIS_POOL = aioredis.ConnectionsPool('redis://47.193.14.198:6379', password="root123", minsize=1, maxsize=10)
@app.get("/")
def index():
    """ 普通操作接口 """
    return {"message": "Hello World"}
@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")
在有多个用户并发请求的情况下,异步方式来编写的接口可以在IO等待过程中去处理其他的请求,提供性能。

例如:同时有两个用户并发来向接口 http://127.0.0.1:5000/red 发送请求,服务端只有一个线程,同一时刻只有一个请求被处理。 异步处理可以提供并发是因为:当视图函数在处理第一个请求时,第二个请求此时是等待被处理的状态,当第一个请求遇到IO等待时,会自动切换去接收并处理第二个请求,当遇到IO时自动化切换至其他请求,一旦有请求IO执行完毕,则会再次回到指定请求向下继续执行其功能代码。

爬虫

在编写爬虫应用时,需要通过网络IO去请求目标数据,这种情况适合使用异步编程来提升性能,
接下来我们使用支持异步编程的aiohttp模块来实现。
安装aiohttp模块
pip3 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))
async def main():
    async with aiohttp.ClientSession() as session:
        url_list = [
            'https://python.org',
            'https://www.baidu.com',
            'https://www.pythonav.com'
        ]
        tasks = [asyncio.create_task(fetch(session, url)) for url in url_list]
        await asyncio.wait(tasks)
if __name__ == '__main__':
    asyncio.run(main())
posted @ 2023-02-02 15:50  技术改变命运Andy  阅读(2128)  评论(0编辑  收藏  举报