同步将任务添加到异步事件循环并确保其执行

问题描述

import asyncio


async def print_number(num):
    if num % 2 == 0:
        await asyncio.sleep(1)
    print(num)


def add_tasks():
    current_loop = asyncio.get_running_loop()
    for i in range(10):
        current_loop.create_task(print_number(i))


async def print_hello():
    print("Hello World!")
    add_tasks()


asyncio.get_event_loop().run_until_complete(print_hello())
# asyncio.get_event_loop().run_until_complete(asyncio.sleep(1.1))

上面的代码产生以下输出

Hello World!
1
3
5
7
9

Process finished with exit code 0

起初,这使我感到惊讶,因为给出了奇数,但是在await之后完成的偶数却没有。取消对sleep行的注释会显示它们。

asycio中读取以下代码说明了原因:使用create_task添加任务可确保一旦循环完成迭代,则在事件循环结束时调用它们,但计划进行任何回调/唤醒直到下一次事件循环迭代时才会执行这些操作-不会发生,因为print_hello()现在已经结束,run_until_complete终止了。

在那种情况下,是否有办法同步(没有await)将协程添加到已经运行的事件循环中并确保执行?如上所述,以上代码无法确保其执行。

在我的实际场景中,add_tasks是一种同步方法,我无法更改其方法签名,只能更改add_tasks方法内容。我也无法控制事件循环的开始方式。

在这一点上,我正在考虑使用其自己的事件循环启动一个新线程,在其中执行协程,并.join()等待其执行。但是有更好的方法吗?

对于上下文...为什么需要这个可能看起来很奇怪,但是不幸的是,这对我来说是一个真实的情况。我在Django信号中,它是一种同步方法,但可能在事件循环中运行(这是一个信号,非常通用的一段代码)。该信号需要运行channel_layer.group_send包提供的异步方法channels。因此,我必须将channel_layer.group_send同步附加到事件循环中(async_to_sync不起作用,因为它会引发异常,告诉您await如果您处于事件循环中)。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)