You need to enable JavaScript to run this app. Python问题:无法在独立线程或事件循环中运行connexion aiohttp服务器
优惠活动
大模型
产品
解决方案
定价
更多

Python问题:无法在独立线程或事件循环中运行connexion aiohttp服务器

问题复现与解决方案

我一直无法将使用aiohttp的connexion服务器放到后台运行,导致启动web服务器时主线程会被阻塞。我知道可以通过asyncio为其余逻辑创建任务实现需求,但我正在开发供其他个人和企业复用的库,无法单方面强制所有使用者统一采用这种设计模式。

我已经实现了原生aiohttp服务的后台运行,代码如下:

import asyncio
import threading
from aiohttp import web
import time

def aiohttp_server():
    def say_hello(request):
        return web.Response(text='Hello, world')

    app = web.Application(debug=True)
    app.add_routes([web.get('/', say_hello)])
    handler = app.make_handler()
    return handler

def run_server(handler):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    server = loop.create_server(handler, host='127.0.0.1', port=8089)
    loop.run_until_complete(server)
    loop.run_forever()

t = threading.Thread(target=run_server, args=(aiohttp_server(),))
t.start()

for i in range(50000):
   print('Hi from Main Thread')
   time.sleep(5)

上述代码可以正常启动服务,同时主线程可以继续执行其他逻辑。但我尝试将该方案适配到connexion服务器时遇到了问题,运行后主线程不会被阻塞,但web服务器完全不响应任何请求,我的实现代码如下:

def initializeServerTest():
    app = connexion.AioHttpApp(__name__, 
        port=8080, 
        specification_dir='openAPISpecs/',
        only_one_api=True
    )
    app.add_api('openAPISpec.json', 
        arguments={'title': 'Instrument and HUB API'}, 
        pythonic_params=True, 
        validate_responses=True
    )
    # 配置CORS
    cors = aiohttp_cors.setup(app.app, defaults={
            "*": aiohttp_cors.ResourceOptions(allow_credentials=True,
                                            expose_headers="*",
                                            allow_headers="*", 
                                            allow_methods=["GET", "POST", "PUT"]
                                            )
    })
    for route in list(app.app.router.routes()):
        cors.add(route)
    
    runner = web.AppRunner(app.create_app())
    return runner

def run_server(runner):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(runner.setup())
    site = web.TCPSite(runner, 'localhost', 8080)
    loop.run_until_complete(site.start())
    loop.run_forever()

def StartServerInBackground():
    t = threading.Thread(target=run_server, args=(initializeServerTest(),))
    t.start()

问题原因

  1. 创建AppRunner时错误调用了app.create_app(),该方法会生成全新的空白aiohttp应用,之前添加的API路由、CORS配置全部没有被应用到最终运行的服务中,导致没有任何请求可以被匹配处理。
  2. 所有依赖asyncio的对象(包括AioHttpApp实例、AppRunner等)都应该在后台线程对应的专属事件循环中创建,原代码在主线程初始化connexion应用,和后台线程的事件循环不属于同一个上下文,会导致异步对象调用异常。

修复后的实现代码

import asyncio
import threading
import time
import connexion
import aiohttp_cors
from aiohttp import web

def run_server():
    # 所有异步相关初始化都放在后台线程的事件循环上下文内执行
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    # 初始化connexion应用
    app = connexion.AioHttpApp(__name__, 
        port=8080, 
        specification_dir='openAPISpecs/',
        only_one_api=True
    )
    app.add_api('openAPISpec.json', 
        arguments={'title': 'Instrument and HUB API'}, 
        pythonic_params=True, 
        validate_responses=True
    )

    # 配置CORS规则
    cors = aiohttp_cors.setup(app.app, defaults={
            "*": aiohttp_cors.ResourceOptions(allow_credentials=True,
                                            expose_headers="*",
                                            allow_headers="*", 
                                            allow_methods=["GET", "POST", "PUT"]
                                            )
    })
    for route in list(app.app.router.routes()):
        cors.add(route)
    
    # 直接使用已经配置完成的app.app创建Runner,不要调用create_app()
    runner = web.AppRunner(app.app)
    loop.run_until_complete(runner.setup())
    site = web.TCPSite(runner, 'localhost', 8080)
    loop.run_until_complete(site.start())
    loop.run_forever()

def StartServerInBackground():
    # 新增daemon=True,避免主进程退出时后台线程挂死
    t = threading.Thread(target=run_server, daemon=True)
    t.start()

# 测试逻辑
if __name__ == "__main__":
    StartServerInBackground()
    for i in range(50000):
        print('Hi from Main Thread')
        time.sleep(5)

内容的提问来源于stack exchange,提问作者Brian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 03:24:00