前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >异步(async)

异步(async)

原创
作者头像
用户8442333
修改2021-05-17 18:02:45
1.2K0
修改2021-05-17 18:02:45
举报
文章被收录于专栏:python知识python知识

由于python多线程的诟病,在此学一下异步模块

1. 协程

介于线程和线程之间的人工‘线程’,可以通过代码进行控制和切换。

在python 中有几种实现方法:

a. yeid 关键字

b. asyncio装饰器

c. async,await关键字 (主流写法)

d. greenlet (早期版本的写法)

1.2 greenlet 实现协程

安装; pip install greenlet

from greenlet import greenletdef func1(): print(10) gr2.switch(6666) # 切换到func2() print(12) gr2.switch()def func2(s): print(9) print(s) gr1.switch() #切换成func1() print(99)gr1 = greenlet(func1)gr2 = greenlet(func2)gr1.switch() #第一步会执行 func1###程序运行后,先打印10,在切换到fun2函数,打印9和666,之后再切换到原函数

yield 关键字

def x1(): yield 1 yield from x2() yield 2 #生成器def x2(): yield 3 yield 4f1 = x1()for i in f1: print(i)1342###yield 本质是一个生成器,通过yield from 达到在函数内跳转的目的

asyncio装饰器,装饰后的函数都是协程

@asyncio.coroutinedef x1(): print('9999') yield from asyncio.sleep(2) #遇到IO耗时操作,自动切换到tasks中其他任务 print(2)@asyncio.coroutinedef x2(): print('666') yield from asyncio.sleep(3) print('0000')tasks = [ asyncio.ensure_future(x1()), asyncio.ensure_future(x2())]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))999966620000

一共耗时3秒。

async & await 关键字

async def x1(): print('9999') await asyncio.sleep(10) #遇到IO耗时操作,自动切换到tasks中其他任务 print(2)async def x2(): print('666') await asyncio.sleep(11) print('0000')tasks = [ asyncio.ensure_future(x1()), asyncio.ensure_future(x2())]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))

2. 异步编程

2.1 事件循环

任务列表 = 【任务1,任务2....】while True: 可执行任务列表,已完成任务列表 = 【任务列表】 for i in 可执行任务列表: for j in 已完成任务列表 如果 任务列表中 没有可执行任务,则终止循环

loop = asyncio.get_event_loop() # 事件循环loop.run_until_complete(asyncio.wait(任务列表))

2.2 定义函数时, async def 函数

async def fun(): print('6666')#创建协程对象,函数内部代码不会执行result = fun() #调用# loop = asyncio.get_event_loop()# loop.run_until_complete(result)asyncio.run(result) #py 3.7 版本,相当于上面2句代码的功能

2.3 await + 可等待对象(协程对象,Future,Task对象)

async def fun(): print('6666') #遇到耗时操作,就去执行第二个函数 await asyncio.sleep(2) print('end') return '返回值'async def func1(): print('执行') response = await fun() print('fun请求结束',response)asyncio.run(func1())执行6666endfun请求结束 返回值

2.4 Task 对象

Task用于并发调度协程,通过asyncio.create_task()的方式创建Task对象,我们可以添加多个任务在其中,当遇到io阻塞时,会去调用其他的任务执行。(python 3.7)

async def x1(): print('1') await asyncio.sleep(2) print('2') return '返回值'async def main(): print('main开始') #创建Task对象,将x1到事件循环taska_list = [ asyncio.create_task(x1()), asyncio.create_task(x1())]print('main结束')done, _ = await asyncio.wait(taska_list)print(done)asyncio.run(main())main开始main结束1122返回值 返

Task 继承Future,Task对象内部await结果的处理是基于Future对象来着

Future:

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,并在2秒后给fut赋值 #手动设置future任务 await loop.create_task(set_after(fut)) # 等待future对象获取,最终结果,否则一直等下去 data = await fut print(data)asyncio.run(main())

小测试:

async def x1(): while 1: print('aaa5秒') await asyncio.sleep(5)async def x2(): while 1: print('bbb4秒') await asyncio.sleep(4)async def x3(): print('ccc3秒') await asyncio.sleep(3)def run(): tasks = [] for i in [x1(),x2(),x3()]: tasks.append(asyncio.ensure_future(i)) loop = asyncio.get_event_loop() # 时间循环 loop.run_until_complete(asyncio.wait(tasks))aaa5秒bbb4秒ccc3秒bbb4秒aaa5秒bbb4秒aaa5秒....

2.5 异步迭代器(了解)

什么是迭代器,就是实现了__iter__()和__next__()方法的对象。而异步迭代器则是是现实了__aiter()__和__aanext()__方法的对象,返回一个awaitable对象。被async_for处理。

class Reader(object): '''自定义异步迭代器''' def __init__(self): self.count = 0 async def readline(self): # await asyncio.sleep(1) self.count +=1 if self.count == 100: return None def __aiter__(self): #返回自身 return self async def __anext__(self): val = await self.readline() #如果为None,则掏出异常 if val == None: raise StopAsyncIteration return val# async for 必须写在协程函数里面async def run(): obj = Reader() async for i in obj: print(i)asyncio.run(run())

2.6 异步上下文管理器

class AsyncContextManager: def __init__(self): self.conn = pymysql.connect(host='127.0.0.1',user='root',passwd='root',db = '',port= '',charset='utf8',connect_timeout=10000) async def do_smoething(self): #异步操作数据库 return 666 async def __aenter__(self): self.conn = await asyncio.sleep(1) return self async def __aexit__(self, exc_type, exc_val, exc_tb): #关闭数据库 await asyncio.sleep(1)async def run(): async with AsyncContextManager() as f: result = await f.do_smoething() print(result)asyncio.run(run())

2.7 uvloop (第三方asynio的事件替代方案) 也是个事件循环,效率比原来的高

安装: pip install uvloop

##但是这个uvloop只支持Linux,不支持WIN

import uvloopasyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

在文件设置以上代码,就可以把asyncio中的loop代替成uvloop

2.8 异步 redis

安装: pip install aioredis

async def execute(adress,password): print('开始执行',adress) # 网络IO操作,链接REDIS redis = await aioredis.create_redis(adress,password=password) # 网络io操作,在redis设置哈希值car,内部在设置3个键值对 #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('结束',adress)asyncio.run(execute('redis://127.0.0.1:6379',"123456"))

上面ip和密码改成你自己的

2.9 异步 mysql

安装: pip install aiomysql

async def execute(host,password): print('开始') conn = await aiomysql.connect(host=host,port=3306,user='root',password=password,db='gungunDb') #获取浮标 cur = await conn.cursor() # await cur.execute("select * from user") # result = await cur.fetchall() print(result) # await cur.close() conn.close() print('结束',host)task_list = [ execute('127.0.0.1','root')]asyncio.run(asyncio.wait(task_list))

注意要异常处理

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档