优势和劣势这是我自己经验瞎说,日后校验
1 异步实现并发的好处那是没的说的但是异步并发编程并不是那么简单和容易,需要 清楚的知道什么地方用异步等,一个函数中可能还有很多地方用到异步,用到异步的时候注意,一旦函数变成异步就不是普通函数,不能像普通函数那样调用了,必须放在特定的异步循环机制中,注册进去,或者所谓的驱动函数才可以。下面使用代码来进行说明
import asyncio
import time
now = lambda: time.time()
async def do_some_work(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = now()
coroutine = do_some_work(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task ret: ', task.result())
print('TIME: ', now() - start)
# 运行结果
# Waiting: 2
# Task ret: Done after 2s
# TIME: 2.0012385845184326
上面这是使用异步调用的可以正常使用下面演示
import asyncio
import time
now = lambda: time.time()
async def do_some_work(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
start = now()
if __name__ == '__main__':
do_some_work(2)
# 运行结果报错
# D:/develop/work/yang/coroutine_about/cor8.py:12: RuntimeWarning: coroutine 'do_some_work' was never awaited
do_some_work(2)
do_some_work() 是声明为了异步方法,使用普通的调用就调用不了了
其实await 和yield 一样后面只要返回的是 future 对象就可以啦
没有 返回future的情况
import asyncio
import time
now = lambda: time.time()
from yang.coroutine_about.operator import make_future
class Yang(object):
def bb(self):
return "aa"
async def do_some_work(self, x):
print('Waiting: ', x)
# await asyncio.sleep(x)
aa = await self.bb()
return 'Done after {}s'.format(aa)
if __name__ == '__main__':
y = Yang()
start = now()
coroutine = y.do_some_work(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task ret: ', task.result())
print('TIME: ', now() - start
# 运行结果
Waiting: 2
File "D:/develop/work/yang/coroutine_about/cor9.py", line 23, in
loop.run_until_complete(task)
File "D:\Programs\Python36\lib\asyncio\base_events.py", line 467, in run_until_complete
return future.result()
File "D:/develop/work/yang/coroutine_about/cor9.py", line 14, in do_some_work
aa = await self.bb()
TypeError: object str can't be used in 'await' expression
加上装饰器 返回函数是一个future 对象只是把函数作为对象的值给返回了 这样就会正常返回
import asyncio
import time
now = lambda: time.time()
from yang.coroutine_about.operator import make_future
class Yang(object):
@make_future
def bb(self):
return "aa"
async def do_some_work(self, x):
print('Waiting: ', x)
# await asyncio.sleep(x)
aa = await self.bb()
return 'Done after {}s'.format(aa)
if __name__ == '__main__':
y = Yang()
start = now()
coroutine = y.do_some_work(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task ret: ', task.result())
# 运行结果
# Waiting: 2
# Task ret: Done after aas
# TIME: 0.0009751319885253906
make_future 的方法
import asyncio
from functools import wraps
def make_future(func):
@wraps(func)
def _make_future(self, *args, **kwargs):
future = asyncio.Future()
result = func(self, *args, **kwargs)
future.set_result(result)
return future
return _make_future
从上面可以看出 await 后面是一个future 对象。获得返回值是存在result 中的 ,task.result() 能够接受到返回的值,值就存在这里。 future 也是用来存值的,对于异步来说,必须是future 存
其实直接给 装饰为future 放在值中或者是 直接声明为异步函数其实都是 获得一个future 对象,这样直接声明函数就好,async 也是一样的
import asyncio
import time
now = lambda: time.time()
from yang.coroutine_about.operator import make_future
class Yang(object):
async def bb(self):
return "aa"
async def do_some_work(self, x):
print('Waiting: ', x)
# await asyncio.sleep(x)
aa = await self.bb()
return 'Done after {}s'.format(aa)
if __name__ == '__main__':
y = Yang()
start = now()
coroutine = y.do_some_work(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print('Task ret: ', task.result())
print('TIME: ', now() - start)
# 运行结果
# Waiting: 2
# Task ret: Done after aas
# TIME: 0.0010013580322265625
运行效果和上面使用future的 效果是一样的
综上所述:
就Python 原生异步 anyncio 来说 需要注意这么几点
1. 使用原生的asyncio 的事件循环来注册函数 ,获得任务task
2. 然后循环执行直到完成
3. 将函数声明为异步了之后就不能作为普通函数调用了,不然会出错。
4. 使用yield 或者await 的时候注意后面的函数返回的是一个future 对象 (直接将函数申明为异步使用 async 关键字或者 直接将函数装饰为future 对象返回)
5. 使用异步的时候 关键字 async 和await 一起使用 的 不能和yield 混用 。当使用asyncio 注解的时候使用yield
6. 为什么使用 future 对象 在其他博客文章中可以找到答案。