如何在辅助线程中运行aiohttp Web应用程序

问题描述:

以下代码摘自aiohttp文档 https://docs.aiohttp.org/zh/稳定/ 确实有效:

The following code taken from the aiohttp docs https://docs.aiohttp.org/en/stable/ does work:

from aiohttp import web

async def handle(request):
    name = request.match_info.get('name', "Anonymous")
    text = "Hello, " + name
    return web.Response(text=text)

app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])

if __name__ == '__main__':
  web.run_app(app)

但是让网络服务器劫持主线程是不可接受的:网络服务器应位于单独的非主线程上,并 subservient 到主后端应用程序.

But having the webserver hijack the main thread is not acceptable: the webserver should be on a separate non-main thread and subservient to the main backend application.

我无法确定如何在辅助线程上运行webapp.这是我尝试过的:

I can not determine how to run the webapp on a secondary thread. Here is what I have tried:

  1. 无法在ipython repl中运行代码段:
  1. It is not possible to run the snippet of code in ipython repl:

我试图以这种方式运行它:

I tried to run it this way:

#if __name__ == '__main__':
web.run_app(app)

并收到有关no current event loop

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3293, in run_code
    async def run_code(self, code_obj, result=None, *, async_=False):
  File "<ipython-input-8-344f41746659>", line 13, in <module>
    web.run_app(app)
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web.py", line 393, in run_app
    def run_app(app: Union[Application, Awaitable[Application]], *,
  File "/usr/local/Cellar/python@3.8/3.8.1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/events.py", line 628, in get_event_loop
    def get_event_loop(self):
RuntimeError: There is no current event loop in thread 'Thread-11'.

那么,.. 什么只能在main中运行?我在这里想念东西.

So then .. what it can only be run in main? I'm missing something here..

我尝试在另一个独立脚本中但在从属线程上运行:

I tried running in another standalone script but on a subservient thread:

def runWebapp():
  from aiohttp import web

  async def handle(request):
      name = request.match_info.get('name', "Anonymous")
      text = "Hello, " + name
      return web.Response(text=text)

  app = web.Application()
  app.add_routes([web.get('/', handle),
                  web.get('/{name}', handle)])
  web.run_app(app)

if __name__ == '__main__':
  from threading import Thread
  t = Thread(target=runWebapp)
  t.start()
  print('thread started let''s nap..')
  import time
  time.sleep(50)

但这基本上给出了相同的错误:

But that gives basically the same error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.8/3.8.1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/local/Cellar/python@3.8/3.8.1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/git/bluej/experiments/python/aio_thread.py", line 12, in runWebapp
    web.run_app(app)
  File "/usr/local/lib/python3.8/site-packages/aiohttp/web.py", line 409, in run_app
    loop = asyncio.get_event_loop()
  File "/usr/local/Cellar/python@3.8/3.8.1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.

那么我该如何从main线程中删除该Web应用程序并使它与我的应用程序中的其他线程一起播放

So how do I get this webapp off the main thread and make it play along with the other threads in my application

在这里:

import http.server
import threading
import socketserver

PORT = 8000

Handler = http.server.SimpleHTTPRequestHandler

def serve_forever():
    with socketserver.TCPServer(("", PORT), Handler) as httpd:
        httpd.serve_forever()

if __name__ == "__main__":
    threading.Thread(target=serve_forever).start()
    while 1:
        x = input("enter a number")
        print("You entered {}".format(x))

这是一个很好的聚会技巧,但对生产工作不一定有用:http.server模块的文档在文档页面顶部的红色火焰中表示不要在生产中使用它.但是,几乎所有的python网络服务器框架都可以作为WSGI服务器使用,并且无法按照您希望的方式运行:它们通常期望由gunicorn或apache之类的东西来运行.

N.B. this is a neat party trick, but not necessarily useful for production work: the documentation for the http.server module says in flaming red letters at the top of the doc page not to use it in production. But almost all python webserver frameworks operate as WSGI servers and aren't designed to work the way you seem to want them to: they generally expect to be run by something else like gunicorn or apache.

我强烈建议您是否需要HTTP服务器,例如监视正在运行的应用程序,您改而使用asyncio并对所有内容使用coros,但如果您确实愿意,可以按上述方式滚动自己的线程方案.您可以看到您仍然可以在无限输入循环中与外壳程序交互,同时还可以卷曲localhost:8000以获取包含目录列表的HTML页面.

I strongly recommend if you need an HTTP server for e.g. monitoring a running app that you use asyncio instead and use coros for everything, but you can roll your own threading scenario as above if you really want to. You can see that you can still interact with the shell in the infinite input loop while you can also curl localhost:8000 to get an HTML page containing a directory listing.

只需传入您自己创建的非默认处理程序即可执行其他操作,例如以JSON格式返回应用程序状态.

Just pass in a non-default handler of your own creation to do other stuff like return app state in JSON format.