首页 > 解决方案 > 如何在辅助线程中运行 aiohttp Web 应用程序

问题描述

以下代码取自aiohttp文档https://docs.aiohttp.org/en/stable/ 确实有效:

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)

在此处输入图像描述

但是让网络服务器劫持主线程是不可接受的:网络服务器应该在一个单独的非主线程上,并且 从属于主后端应用程序。

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

  1. 无法在ipythonrepl 中运行代码片段:

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

#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地方?我在这里遗漏了一些东西..

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

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)

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

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'.

那么如何让这个 webapp 脱离main线程并让它与我的应用程序中的其他线程一起玩

标签: pythonaiohttp

解决方案


干得好:

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 webserver 框架都作为 WSGI 服务器运行,并且没有按照您希望它们的方式工作:它们通常期望由 gunicorn 或 apache 之类的其他东西运行。

如果你需要一个 HTTP 服务器来监控一个正在运行的应用程序,我强烈建议你使用 asyncio 来代替,并为所有事情使用 coros,但是如果你真的想要的话,你可以像上面那样滚动你自己的线程场景。您可以看到您仍然可以在无限输入循环中与 shell 交互,同时您还可以 curl localhost:8000 来获取包含目录列表的 HTML 页面。

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


推荐阅读