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

Python multiprocessing.Queue 出现死锁问题求助

Python multiprocessing.Queue 出现死锁问题求助

看起来你的问题大概率是子进程在完成文件读取后,后续代码触发了未被捕获的异常,导致子进程直接退出,根本没执行到results_queue.put()这一步,父进程就一直卡在get()上等着,形成了死锁。结合你看到的日志——子进程打印了“Finished reading”但没打印“Child process returning result”,正好印证了这一点。

我给你分析几个关键点和解决办法:

1. 先排查异常捕获范围的问题

你当前的except Exception as e只能捕获常规的异常,但Python里像KeyboardInterrupt、SystemExit甚至一些底层的信号终止(比如被系统OOM Killer干掉)都不属于Exception的子类,这些情况会直接让子进程崩溃,不会进入你的except块,自然也就不会执行put()。

建议把捕获范围扩大到BaseException,并且加上finally块确认子进程的退出状态:

def _process_pdf_pages(original_file, arg1, arg2, arg3,..., results_queue):
    try:
        logger.info('{} Started reading PDF/XPS file {}'.format(dt.datetime.now(), original_file))
        # ... 读取文件的代码
        logger.info('{} Finished reading PDF/XPS file {}'.format(dt.datetime.now(), original_file))
        # --- 这里加更多日志,定位卡在哪一步 ---
        logger.info('Starting post-processing steps')
        # ... 你原来的后续处理代码
        logger.info('Child process returning result')
        results_queue.put((arg1, arg2, arg3...))
    except BaseException as e:
        logger.error('Child process encountered FATAL error: {}'.format(e))
        logger.error(traceback.format_exc())
        logger.info('Child process returning error marker')
        # 可以在返回结果里加个错误标记,让父进程知道出问题了
        results_queue.put((arg1, arg2, arg3, None))
    finally:
        logger.info('Child process is exiting now')

2. 给父进程的get()加超时保护

一直无限等待肯定不是办法,给get()加个超时时间,这样即使子进程挂了,父进程也不会一直卡死,还能检查子进程的退出状态:

import queue

def parent_function():
    # ... 其他代码
    results_queue = multiprocessing.Queue()
    child_process = multiprocessing.Process(target=_process_pdf_pages, args=(original_file, arg1, arg2, arg3,..., results_queue))
    child_process.start()
    logger.info('BEGIN results = results_queue.get()')
    try:
        # 比如设置60秒超时,根据你的处理时间调整
        results = results_queue.get(timeout=60)
        logger.info('END results = results_queue.get()')
    except queue.Empty:
        logger.error('Timeout waiting for child process result')
        # 检查子进程是否还活着
        if child_process.is_alive():
            logger.warning('Child process is still running, force terminating it')
            child_process.terminate()
            child_process.join()
        else:
            logger.info(f'Child process exited with code: {child_process.exitcode}')
            # 退出码是负数的话,说明是被信号终止的(比如SIGKILL)
            if child_process.exitcode < 0:
                logger.error(f'Child process was killed by signal: {-child_process.exitcode}')
    # ... 其他代码

3. 定位子进程卡死的具体位置

在“Finished reading”之后的每一段代码前都加上日志,比如:

logger.info('Starting page analysis')
# ... 页面分析代码
logger.info('Page analysis done, starting result formatting')
# ... 结果格式化代码

这样下次出现死锁时,你就能通过日志知道子进程到底执行到哪一步停了,精准定位问题代码。

其他可能的小概率原因

  • 子进程被系统资源限制干掉了:比如内存不足被OOM Killer终止,这种情况子进程的退出码会是负数(比如-9对应SIGKILL),可以通过child_process.exitcode查看。
  • multiprocessing.Queue的缓冲区问题:不过你只put一次结果,缓冲区不可能满,这个可能性极低。

先按上面的方法调整代码,应该能解决你的死锁问题,或者至少能定位到具体原因。

备注:内容来源于stack exchange,提问作者Travis Lu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 10:22:59