繁体   English   中英

异步函数完成后的Python调用回调

[英]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是你所知道的一切的黑匣子,你不知道它在等待什么或为什么,或者可以在它睡觉时明确地从它那里获得控制权。

因此,将asyncfunctionprint('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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM