将 gunicorn 与 asyncio 一起使用时,如何屈服于另一个请求?

How do I yield to another request when using gunicorn with asyncio?

我正在尝试将 Gunicorn 中的 gaiohttp worker 与我正在使用以下命令开发的 Django 应用程序一起使用:

gunicorn -k gaiohttp -b localhost:8080 myproject.wsgi

我的最终目标是能够同时处理请求——即让 1 个 gunicorn worker 同时处理多个请求。有 I/O 个绑定操作使这些请求变慢。

我知道在处理请求时事件循环已经 运行:

class MyView(View):

    def get(self, request):
        loop = asyncio.get_event_loop()
        loop.is_running() # True
        ...

问题:

  1. 如何在我的视图代码中执行诸如 yield from asyncio.sleep(10) 之类的操作?

    class MyView(View):
    
        def get(self, request):
            # Raises AssertionError: yield from wasn't used with future
            yield from asyncio.sleep(10)
    
  2. 我可以将任务添加到事件循环中,但是它们在处理请求时不会阻塞

    @asyncio.coroutine
    def simulate_work():
        yield from asyncio.sleep(10)
    
    class MyView(View):
    
        def get(self, request):
            # This runs simulate_work(), however, it doesn't block 
            # the response is returned before simulate_work() is finished
            loop = asyncio.get_event_loop()
            task = loop.create_task(simulate_work())
    
  3. 我尝试使用futures,但是事件循环已经运行

    @asyncio.coroutine
    def simulate_work(future):
        yield from asyncio.sleep(10)
        future.set_result('Done!')
    
    class MyView(View):
    
        def get(self, request):
            future = asyncio.Future()
            asyncio.async(simulate_work(future))
            loop = asyncio.get_event_loop()
            # Raises RuntimeError: Event loop is running.
            loop.run_until_complete(future)
            print(future.result())
    

很明显,我对 asyncio 或 gaiohttp 有一些不了解的地方。

如何让 asyncio.sleep(10) 阻止当前请求,但不阻止 gunicorn 处理其他请求?

抱歉,您不能从 wsgi 应用程序调用协同程序 -- WSGI 是 同步 协议,以及构建在它之上的框架(Django、Flask、Pyramid)。

我已经实现了 gaiohttp 工人,但它是异步世界中的第二个 class 公民。如果您确实需要异步 HTTP 服务器,请尝试 aiohttp.web