0
import asyncio
from asgiref.sync import sync_to_async


@sync_to_async
def sync_func():
    print("sync_func() was CALLED (good!)")


async def async_func():
    print("async_func() was CALLED (good!)")


async def test(excep_type: type = asyncio.CancelledError):
    print(f"\nException Type: {excep_type}")
    try:
        raise excep_type
    except:
        await async_func()
        try:
            await sync_func()
        except asyncio.CancelledError:
            print("sync_func() was CANCELLED (bad!)")

asyncio.run(test(excep_type=ValueError))
asyncio.run(test())

你好呀。我有一个简单的例子

  1. test是一个异步函数,除了引发提供的错误类型,然后在async_func内部等待sync_func
  2. sync_funcsync_to_async是一个与asgiref 包异步的同步函数。

运行它会给出以下输出:

Exception Type: <class 'ValueError'>
async_func() was CALLED (good!)
sync_func() was CALLED (good!)

Exception Type: <class 'asyncio.exceptions.CancelledError'>
async_func() was CALLED (good!)
sync_func() was CANCELLED (bad!)

在第一种情况下,在异常子句中ValueError引发,我可以正常等待。async_funcsync_func

但是在第二种情况下,我有我不期望的行为。我应该能够sync_func像往常一样等待,但它反而会asyncio.CancelledError如打印输出所示引发。

实际上,我没有更改两次调用之间的任何内容,只是更改了异常子句最初引发和捕获的错误类型。然而,引发错误的类型似乎产生了影响。

这在现实世界中意味着什么,我不能在取消任务sync_to_async的任何清理活动中使用包装的异步函数

这似乎是由sync_to_async装饰器引起的,async_func运行良好。

我究竟做错了什么?

4

1 回答 1

0

这是sync_to_asyncasgiref 3.3.1 中引入的一个错误。

https://github.com/django/asgiref/issues/247

这可以使用内置的 asyncio 功能解决,或者,如果不可能,将失败的协程包装在create_task.

于 2021-03-25T16:33:27.983 回答