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 个线程。然后他们将以循环方式服务请求。

所以场景是:

  1. 用户点击 /createloop(给定线程 1)
  2. 用户点击 /useorm(给定线程 2)
  3. 用户再次点击 /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) 解决了它。