uWSGI线程有现有的运行事件循环导致Django的SynchronousOnlyOperation异常
uWSGI thread has existing running event loop which causes Django's SynchronousOnlyOperation exception
我有两个 Django 视图,
def view_that_accesses_orm(request): # say end point /useorm
user = User.objects.first()
...
和
def view_that_creates_event_loop(request): # say endpoint /createloop
client = AsycProvider()
... # do stuff with client
和AsyncProvider
类似于
class AsyncProvider:
def __init__(self):
try:
self.__loop = asyncio.get_event_loop()
except RuntimeError as e:
print(e) #no running event loop
self.__loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.__loop)
self.__session = aiohttp.ClientSession(loop=self.__loop)
... # other operations with asyncio.run_until_complete, asyncio.gather, and self.__session
现在的问题是如果我在 uWSGI 中有 1 个进程和 2 个线程。然后他们将以循环方式服务请求。
所以场景是:
- 用户点击
/createloop
(给定线程 1)
- 用户点击
/useorm
(给定线程 2)
- 用户再次点击
/useorm
(给定线程 1)
现在在第三种情况下,有时事件循环是 运行 并且由于 Django 3.x 检测到 运行 事件循环并不允许我们访问 ORM,我得到 django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
异常。
我不确定事件循环如何不停止并持续存在于线程中。
请解释造成这种情况的确切原因以及应该如何解决?
问题是 AsyncProvider
方法内部某处使用了 asyncio.set_event_loop(self.__loop)
。
所以在不同的线程中引用了相同的循环实例(没有创建新循环)。现在因为这个循环有时也会有一些 运行 逻辑,而且如果在一个线程中(引用这个循环)ORM 被访问,Django 抛出 SynchronousOnlyOperation
因为它可以检测到 运行事件循环。
通过删除方法中的 asyncio.set_event_loop(self.__loop)
解决了它。
我有两个 Django 视图,
def view_that_accesses_orm(request): # say end point /useorm
user = User.objects.first()
...
和
def view_that_creates_event_loop(request): # say endpoint /createloop
client = AsycProvider()
... # do stuff with client
和AsyncProvider
类似于
class AsyncProvider:
def __init__(self):
try:
self.__loop = asyncio.get_event_loop()
except RuntimeError as e:
print(e) #no running event loop
self.__loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.__loop)
self.__session = aiohttp.ClientSession(loop=self.__loop)
... # other operations with asyncio.run_until_complete, asyncio.gather, and self.__session
现在的问题是如果我在 uWSGI 中有 1 个进程和 2 个线程。然后他们将以循环方式服务请求。
所以场景是:
- 用户点击
/createloop
(给定线程 1) - 用户点击
/useorm
(给定线程 2) - 用户再次点击
/useorm
(给定线程 1)
现在在第三种情况下,有时事件循环是 运行 并且由于 Django 3.x 检测到 运行 事件循环并不允许我们访问 ORM,我得到 django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
异常。
我不确定事件循环如何不停止并持续存在于线程中。
请解释造成这种情况的确切原因以及应该如何解决?
问题是 AsyncProvider
方法内部某处使用了 asyncio.set_event_loop(self.__loop)
。
所以在不同的线程中引用了相同的循环实例(没有创建新循环)。现在因为这个循环有时也会有一些 运行 逻辑,而且如果在一个线程中(引用这个循环)ORM 被访问,Django 抛出 SynchronousOnlyOperation
因为它可以检测到 运行事件循环。
通过删除方法中的 asyncio.set_event_loop(self.__loop)
解决了它。