zoukankan      html  css  js  c++  java
  • 异步编程

    实战案例

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

    异步 - Reids

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

    安装Python异步操作redis模块

    pip3 install aioredis
    

    示例1:异步操作redis。

    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搭建。

    接下里的异步示例以FastAPIuvicorn来讲解(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())
    

    总结

    为了提升性能越来越多的框架都在向异步编程靠拢,例如:sanic、tornado、django3.0、django channels组件 等,用更少资源可以做处理更多的事,何乐而不为呢。

  • 相关阅读:
    UIWebvView 解决onClick 延迟相应问题
    MySQL 5.6.x 配置数据库主从复制
    SDWebImage 常用方法
    OSX/iOS 播放系统声音
    UIView 设置阴影(属性说明)
    Response的Content-Type一览
    Linux查看端口占用情况并释放端口占用
    Windows安装配置Anaconda2/PyCharm
    bui框架nav导航图标一览
    服务器验证码乱码问题记录(字体库添加)
  • 原文地址:https://www.cnblogs.com/jiangchunsheng/p/12973406.html
Copyright © 2011-2022 走看看