You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python asyncio任务未执行却报告已完成?

问题

为什么任务aioStartServerTask还没执行完核心启动逻辑就报告已完成?正常执行的话,日志里应该出现here和服务器启动的相关输出,但实际没有,而且app.aioServer始终是None,最终触发AttributeError异常。

环境:Python 3.12

相关代码:

from os import path as ospath
import asyncio
import socket as Socket
import logger as log

logger = log.getLogger(fileName=ospath.join('log', 'server.log'), initialize=True)

class App():
    def __init__(self) -> None:
        self.quit = False
        self.aioServer = None
        self.clients = []

    async def clientHandler(self, reader, writer):
        logger.info('client handler starting')

    async def aioServerStart(self):
        logger.info('aioServerStart')
        async def startServer(x=self):
            logger.info('here')
            ipaddr = Socket.gethostbyname(Socket.gethostname())
            port = 32843
            logger.info(f'starting socket server ({ipaddr}:{port})')
            x.aioServer = await asyncio.start_server(self.clientHandler, ipaddr, port=32843)
        return startServer

async def main():
    logger.info("server app starting")
    app = App()
    
    aioStartServerTask = asyncio.create_task(app.aioServerStart())
    logger.info(f'task done: {aioStartServerTask.done()}')
    logger.info('waiting for server to start...')
    await aioStartServerTask
    while not aioStartServerTask.done():
        await asyncio.sleep(.5)
        logger.info('waiting...')
    logger.info(f'task done: {aioStartServerTask.done()}')
    await asyncio.sleep(2)
    await aioStartServerTask
    logger.info('closing server')
    app.aioServer.close()
    await app.aioServer.wait_closed()
    logger.info('server closed')

if __name__ == '__main__':
    asyncio.run(main())

运行输出:

$ python server.py 
    INFO - 2024-09-29 19:42:49,861 - root - initialized logger - None
    INFO - 2024-09-29 19:42:49,861 - root - server app starting
    INFO - 2024-09-29 19:42:49,861 - root - task done: False
    INFO - 2024-09-29 19:42:49,862 - root - waiting for server to start...
    INFO - 2024-09-29 19:42:49,862 - root - aioServerStart
    INFO - 2024-09-29 19:42:49,862 - root - task done: True
    INFO - 2024-09-29 19:42:51,864 - root - closing server
Traceback (most recent call last):
  File "/home/david/python/opcua/server.py", line 79, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/david/python/opcua/server.py", line 74, in main
    app.aioServer.close()
    ^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'close'

解答

问题核心是aioServerStart这个异步函数根本没执行启动服务器的逻辑:它只是定义了内部的startServer协程函数,然后直接返回了这个函数,没有调用执行它。

当你await aioStartServerTask时,任务完成的标志是aioServerStart函数执行完毕——也就是返回内部函数就算完成了,而真正负责启动服务器的startServer协程从未被运行,所以日志里没有here的输出,app.aioServer也一直是None。

修复方案

直接去掉多余的内部嵌套函数,把启动逻辑放在aioServerStart里直接执行:

async def aioServerStart(self):
    logger.info('aioServerStart')
    logger.info('here')
    ipaddr = Socket.gethostbyname(Socket.gethostname())
    port = 32843
    logger.info(f'starting socket server ({ipaddr}:{port})')
    self.aioServer = await asyncio.start_server(self.clientHandler, ipaddr, port=32843)

如果一定要保留内部函数的写法,需要在aioServerStart里调用并await这个内部协程:

async def aioServerStart(self):
    logger.info('aioServerStart')
    async def startServer(x=self):
        logger.info('here')
        ipaddr = Socket.gethostbyname(Socket.gethostname())
        port = 32843
        logger.info(f'starting socket server ({ipaddr}:{port})')
        x.aioServer = await asyncio.start_server(self.clientHandler, ipaddr, port=32843)
    await startServer()  # 关键:执行并等待内部协程完成

另外main里那段while not aioStartServerTask.done()的循环是多余的——await本身就会等待任务完成才继续执行,这段循环永远不会被触发。

修复后,app.aioServer会被正确初始化,日志会出现预期输出,关闭服务器的代码也能正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:09:54