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

Python3.4.3中用create_subprocess_exec调用无限进程遇异常忽略问题

解决Python 3.4.3 asyncio中取消tail -f子进程时的异常问题

我来帮你搞定这个问题,你遇到的Exception ignored in:异常,本质是tailf协程被取消时没有正确终止子进程,或者异常处理逻辑不完整导致的。当asyncio取消任务时会抛出CancelledError,如果没妥善处理这个异常并清理子进程资源,就会引发残留进程相关的忽略异常。

问题分析

你的原代码里,except BaseException ...的处理不完整:

  • 没有明确捕获CancelledError并终止tail子进程
  • 子进程如果没有被主动终止,即便协程被取消,它还会继续运行,进而导致后续的异常提示

修正后的解决方案

下面是完整的可运行代码,我会详细标注关键修复点:

import asyncio
import time

@asyncio.coroutine
def tailf():
    proc = None
    try:
        create = asyncio.create_subprocess_exec(
            'tail', '-f', '/tmp/file',
            stdout=asyncio.subprocess.PIPE,
        )
        proc = yield from create
        while True:
            # 读取行时也可能被取消,所以这里要处理CancelledError
            line = yield from proc.stdout.readline()
            if not line:
                break  # 子进程退出时readline返回空
            print(line.decode('utf-8').strip())
    except asyncio.CancelledError:
        # 当协程被取消时,主动终止子进程
        if proc is not None and proc.returncode is None:
            proc.terminate()
            # 等待子进程结束(可选,确保资源完全释放)
            yield from proc.wait()
        # 重新抛出异常,让asyncio知道任务已被取消
        raise
    except BaseException as e:
        print(f"tailf出现异常: {e}")
        # 如果子进程还在运行,也要终止
        if proc is not None and proc.returncode is None:
            proc.terminate()
            yield from proc.wait()

@asyncio.coroutine
def other_task():
    # 模拟其他耗时任务,运行5秒后完成
    print("其他任务开始运行...")
    yield from asyncio.sleep(5)
    print("其他任务完成")

def main():
    loop = asyncio.get_event_loop()
    # 创建tailf任务
    tail_task = asyncio.ensure_future(tailf())
    # 创建其他任务
    other_future = asyncio.ensure_future(other_task())
    
    # 等待其他任务完成
    loop.run_until_complete(other_future)
    
    # 取消tail任务并等待它结束
    print("准备取消tail任务...")
    tail_task.cancel()
    try:
        loop.run_until_complete(tail_task)
    except asyncio.CancelledError:
        # 这里捕获是正常的,因为我们主动取消了任务
        print("tail任务已被取消并结束")
    
    # 关闭事件循环
    loop.close()
    print("事件循环已关闭")

if __name__ == "__main__":
    main()

关键修复说明

  1. 捕获CancelledError并终止子进程:当tailf任务被取消时,先检查子进程是否还在运行,调用proc.terminate()终止它,再用proc.wait()等待它完全退出,避免残留进程。
  2. 重新抛出CancelledError:这一步是必须的,让asyncio框架正确识别任务已被取消,避免后续的异常提示。
  3. 处理readline()的取消场景:yield from proc.stdout.readline()在等待输入时也可能被取消,所以外层的异常捕获能覆盖这个情况。
  4. 完整的异常清理逻辑:在BaseException块里也加入子进程终止逻辑,确保任何异常情况下都能清理资源。

这样修改后,当其他任务完成后,tail子进程会被优雅终止,协程也能正常退出,不会再出现Exception ignored in:的异常提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:44:58