[英]Python call callback after async function is done
一旦异步函数运行完毕,我就会尝试调用回调
这是我尝试做的一个例子:
import asyncio
async def asyncfunction():
print('Hello')
await asyncio.sleep(10)
print('World')
return 10
def callback(n):
print(f'The async function returned: {n}')
loop = asyncio.get_event_loop()
# Will block the print until everything is done
callback(loop.run_until_complete(asyncfunction()))
print('Hey')
这是它的作用:
Hello
World
The async function returned: 10
Hey
这就是我想要它做的
编辑:“嘿”的位置并不重要,只要它不必等待异步功能完成即可
Hello
Hey
World
The async function returned: 10
编辑:经过一些测试,我找到了一种可以做我想做的事情,虽然我不知道它是否是最好的方法
import asyncio
import threading
async def asyncfunction():
print('Hello')
await asyncio.sleep(10)
print('World')
return 10
def callback(n):
print(f'The async function returned: {n}')
def wrapper(loop):
callback(loop.run_until_complete(asyncfunction()))
loop = asyncio.get_event_loop()
thr = threading.Thread(target=wrapper,args=(loop,))
thr.start()
print('Hey')
将线程与 asyncio 一起使用只会令人困惑,而且很可能不是您想要的。 run_until_complete
是阻塞调用之一,应该是asyncio
程序中的最后一条语句。
要在调用异步函数后添加代码,只需创建一个包装器
async def myfunc():
n = await asyncfunction()
callback(n)
loop.run_until_complete(myfunc()) # from python 3.7, asyncio.run(myfunc())
如果您只想安排一些代码异步运行并继续执行其他操作,请创建一个任务并在最后等待
async def a_main():
task = asyncio.ensure_future(myfunc()) # from python 3.7, asyncio.create_task(...)
print("Hey")
# Anything else to run
await task # wait for the task to complete
loop.run_until_complete(a_main())
免责声明: Following code creates different threads for each function.
这在某些情况下可能很有用,因为它更易于使用。 但是要知道它不是异步的,而是使用多线程产生异步的错觉,即使装饰者建议这样做。
要使任何函数非阻塞,只需复制装饰器并使用回调函数作为参数装饰任何函数。 回调函数将接收函数返回的数据。
import asyncio
import requests
def run_async(callback):
def inner(func):
def wrapper(*args, **kwargs):
def __exec():
out = func(*args, **kwargs)
callback(out)
return out
return asyncio.get_event_loop().run_in_executor(None, __exec)
return wrapper
return inner
def _callback(*args):
print(args)
# Must provide a callback function, callback func will be executed after the func completes execution !!
@run_async(_callback)
def get(url):
return requests.get(url)
get("https://google.com")
print("Non blocking code ran !!")
要获得该命令,您需要在print('Hey')
之后继续执行协程。 您还需要在asyncfunction
睡眠状态时在“ asyncfunction
'Hey'
打印'Hey'
。 这基本上只能由事件循环本身安排; 因为asyncfunction
是你所知道的一切的黑匣子,你不知道它在等待什么或为什么,或者可以在它睡觉时明确地从它那里获得控制权。
因此,将asyncfunction
和print('Hey')
作为异步任务执行,并且主要希望调度成功,以便在asyncfunction
休眠时调度 'Hey' 运行。
val, *_ = loop.run_until_complete(asyncio.gather(
asyncfunction(),
asyncio.coroutine(print)('Hey')
))
callback(val)
asyncio.coroutine(print)
将print
转换为async
函数,并同时在事件循环上gather
计划,并且可能会在asyncfunction
休眠时执行print
。
这是我的解决方案,以及一个名为run_with_callback
的工具函数
# problem
async def asyncfunction(n):
print(f'before sleep in asyncfunction({ n })')
await asyncio.sleep(1)
print(f'after sleep in asyncfunction({ n })')
return f'result of asyncfunction({ n })'
def callback(r):
print(f'inside callback, got: {r}')
# straightforward solution
import asyncio
async def wrapper(n):
r = await asyncfunction(n)
callback(r)
asyncio.get_event_loop().create_task(wrapper(1))
print('sync code following loop.create_task(1)')
asyncio.get_event_loop().create_task(wrapper(2))
print('sync code following loop.create_task(2)')
# general solution with a tool function
def run_with_callback(co):
def wrapper(callback):
task = asyncio.get_event_loop().create_task(co)
task.add_done_callback(lambda t: callback(t.result()))
return callback
return wrapper
# use as function
run_with_callback(asyncfunction(3))(callback)
print('sync code following loop.create_task(3)')
# use as decorator
@run_with_callback(asyncfunction(4))
def _tmp_callback_1(r):
callback(r)
print('sync code following loop.create_task(4)')
# main
_all = asyncio.gather(*asyncio.all_tasks(asyncio.get_event_loop()))
asyncio.get_event_loop().run_until_complete(_all)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.