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

Python多进程join()未等待target_function执行完成的原因排查

问题描述

在多进程实验中,使用multiprocessing.Process创建守护进程,target_function会随机休眠5-10秒后输出内容并向队列存值。多次调用t1函数后出现以下现象:

  • 进程is_alive()返回False、exit_code为0,但join()并未等待target_function的print/日志输出完成
  • 部分进程的target_function输出滞后到后续进程启动后才出现
复现代码
import multiprocessing
import random, time
import logging
from logging.handlers import RotatingFileHandler
logging.basicConfig(
    handlers=[RotatingFileHandler('log.txt')],level=logging.INFO)
logger = logging.getLogger(__name__)

TIMEOUT = 5

PID = None

def target_function(queue_1):
    sleep_value = random.choice(range(5,10))
    time.sleep(sleep_value)
    print('target_function', sleep_value)
    logger.info(f'target_function {sleep_value}')
    queue_1.put(True)


def t1():
    print('###############')
    logger.info('###############')
    queue_1 = multiprocessing.Queue()
    queue_value = False

    process = multiprocessing.Process(target=target_function, args=(queue_1, ))
    process.daemon = True
    process.start()
    PID = process.pid
    
    time.sleep(TIMEOUT)
    
    if not queue_1.empty():
        queue_value = queue_1.get(timeout=3)

    print(PID, queue_value)
    logger.info(f'PID: {queue_value}')

    queue_1.close()

    process.join()

    print(PID, process.is_alive(), process.exitcode)
    logger.info(f'PID: {process.is_alive()}, {process.exitcode}')

    del process


t1()
t1()
原因分析

1. 标准输出(stdout)的缓冲延迟

Python的print函数默认采用行缓冲机制,但在多进程环境下,子进程的stdout缓冲区不会实时刷新到终端。只有当子进程终止、缓冲区满,或者主动调用刷新操作时,缓冲内容才会输出。当你调用process.join()时,会等待子进程执行完毕,子进程终止时才会触发stdout缓冲区的刷新,而此时主进程可能已经进入下一次t1调用,导致子进程的输出看起来滞后到后续进程启动之后。

2. 日志处理器的进程不安全问题

你使用的RotatingFileHandler并非进程安全的日志组件。多个子进程同时向同一个日志文件写入内容时,会存在资源竞争,导致日志内容的写入顺序错乱、延迟甚至部分丢失。这也是日志输出滞后的重要原因之一。

3. 执行时序的不匹配

target_function的休眠时间为5-10秒,而t1函数中固定休眠5秒后才执行后续逻辑。当target_function的休眠时间超过5秒时,子进程在t1执行process.join()时仍在运行,join()会等待子进程结束,但子进程的输出缓冲要到进程终止时才会刷新,这就导致输出在join()之后才出现,而此时主进程可能已经启动了下一个t1的进程,造成输出滞后的错觉。

补充解决建议
  • 强制刷新stdout:在print语句中添加flush=True参数,比如print('target_function', sleep_value, flush=True),确保输出实时刷新。
  • 使用进程安全的日志方案:采用logging.handlers.QueueHandler+QueueListener的组合,让主进程统一处理日志写入,避免多进程直接操作日志文件。
  • 优化等待逻辑:不要依赖固定时长的time.sleep,而是通过队列的get方法(不带超时或合理超时)等待子进程的结果,或者使用multiprocessing.Event来同步子进程的执行状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:00:14