如何在多进程环境中安全地跨进程终止子进程

大晨小哥_6022

大晨小哥_6022

2026-10-04

436人浏览

原创

如何在多进程环境中安全地跨进程终止子进程

本文介绍在 Python 多进程场景下,如何安全、可靠地让一个进程主动终止另一个进程中启动的 subprocess.Popen 实例,避免因竞态条件导致的 AttributeError: 'NoneType' object has no attribute 'terminate' 错误。

本文介绍在 python 多进程场景下,如何安全、可靠地让一个进程主动终止另一个进程中启动的 subprocess.popen 实例,避免因竞态条件导致的 attributeerror: 'nonetype' object has no attribute 'terminate' 错误。

在使用 multiprocessing 启动多个独立进程(如 Blender 渲染 + nvidia-smi 监控)时,常见的误区是依赖全局变量(如 nvidia_cmd = None)跨进程共享子进程句柄。但需明确:Python 中的全局变量在不同 multiprocessing.Process 间完全隔离,父进程或子进程对全局变量的修改不会自动同步到其他进程内存空间中。 因此,run_blender 中访问的 nvidia_cmd 始终为初始值 None,而 run_nvidia 中对其的赋值仅影响自身进程副本——这正是 AttributeError 的根本原因。

要实现跨进程协同控制,必须使用进程间通信(IPC)机制。推荐采用 multiprocessing.Queue(线程/进程安全、轻量、阻塞可控),而非全局变量或 multiprocessing.Manager 等更重方案。以下是完整、健壮的实现:

import multiprocessing
import subprocess
import time

# 命令配置(请按实际路径调整)
BLENDER_CMD = '/home/mickey/dev/blender-4.2.1-linux-x64/blender -b /home/mickey/dev/elastic_shared_memory/benchmark_scenes/bmw27/bmw27.blend -f 10 -- --cycles-device CUDA'
NVIDIA_CMD = 'nvidia-smi --query-gpu=gpu_bus_id,memory.used --format=csv -l 1'

def run_blender(queue):
    """启动 Blender 并在完成时向监控进程发送终止信号"""
    print("[Blender] 开始渲染...")
    blender_proc = subprocess.Popen(BLENDER_CMD, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # 实时输出日志
    for line in iter(blender_proc.stdout.readline, b''):
        print(f"[Blender] {line.decode().strip()}")

    blender_proc.wait()  # 等待渲染结束
    print("[Blender] 渲染完成,通知 GPU 监控进程终止...")
    queue.put("TERMINATE")  # 发送终止指令

def run_nvidia(queue):
    """启动 nvidia-smi 监控,并监听终止信号"""
    print("[nvidia-smi] 启动 GPU 监控...")
    nvidia_proc = subprocess.Popen(NVIDIA_CMD, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    try:
        # 持续读取输出,同时检查终止信号
        while nvidia_proc.poll() is None:  # 进程仍在运行
            # 非阻塞检查队列(避免卡死)
            if not queue.empty():
                signal = queue.get_nowait()
                if signal == "TERMINATE":
                    print("[nvidia-smi] 收到终止信号,正在停止...")
                    nvidia_proc.terminate()
                    nvidia_proc.wait(timeout=3)  # 最多等待3秒
                    break

            # 读取一行输出(带超时避免永久阻塞)
            try:
                line = nvidia_proc.stdout.readline(timeout=0.5)
                if line:
                    print(f"[nvidia-smi] {line.decode().strip()}")
            except subprocess.TimeoutExpired:
                continue

    except Exception as e:
        print(f"[nvidia-smi] 执行异常: {e}")
    finally:
        # 确保进程已清理
        if nvidia_proc.poll() is None:
            nvidia_proc.kill()
        print("[nvidia-smi] 监控进程已退出")

if __name__ == '__main__':
    # 创建 IPC 队列
    control_queue = multiprocessing.Queue()

    # 启动两个进程,传入队列
    blender_p = multiprocessing.Process(target=run_blender, args=(control_queue,))
    nvidia_p = multiprocessing.Process(target=run_nvidia, args=(control_queue,))

    # 先启动监控,再启动渲染(确保监控就绪)
    nvidia_p.start()
    time.sleep(1)  # 留出初始化时间(可选,增强鲁棒性)
    blender_p.start()

    # 等待两者结束
    blender_p.join()
    nvidia_p.join()

    print("所有进程执行完毕。")

关键注意事项:

  • ✅ 永远不要依赖跨进程全局变量:multiprocessing 中每个子进程拥有独立内存空间,全局变量不共享。
  • ✅ 使用 queue.get_nowait() 或带超时的 get(timeout=...):避免在无信号时无限阻塞,影响日志实时性。
  • ✅ 始终处理 subprocess 的生命周期:调用 terminate() 后建议 wait() 或 kill() 确保资源释放;使用 try/finally 保证异常时也能清理。
  • ✅ 启动顺序与同步:示例中先启 nvidia_p 并延时,确保其 Popen 完成后再由 blender_p 发送信号,消除竞态。若需更强同步,可配合 multiprocessing.Event。

该方案简洁、可移植、符合 Python 最佳实践,适用于任何需要跨进程协调子进程生命周期的场景。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1651

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4044

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1649

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

23397

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2867

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2907

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1143

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2243

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习