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

Python并行处理:能否摆脱if __name__ == '__main__'实现模块自包含?

解决Flir相机采集模块无需客户端添加if __name__ == '__main__'的方案

针对你的需求,以下是几种无需客户端手动添加if __name__ == '__main__'判断、实现模块自包含的可行方案:

方案1:模块内封装主进程判断的启动函数

通过在模块内部的启动函数中检测当前进程是否为主进程,子进程调用时直接退出,避免重复执行主程序逻辑。

模块实现(ImageAcquisition.py)

import multiprocessing as mp
import sys
from typing import List

def _camera_worker(cam_id: str):
    # 相机采集、分析逻辑
    while True:
        # 模拟采集处理
        print(f"Processing frame from {cam_id}")
        # 向主进程返回结果的逻辑(如队列、管道)

def Initialize(*cam_ids: str) -> List[mp.Process]:
    processes = []
    for cam in cam_ids:
        p = mp.Process(target=_camera_worker, args=(cam,))
        processes.append(p)
        p.start()
    return processes

def run(cam_ids: List[str]):
    # 仅主进程执行后续逻辑
    if mp.current_process().name != 'MainProcess':
        sys.exit(0)
    # 初始化相机进程
    Initialize(*cam_ids)
    # 主进程可在此添加其他逻辑,或保持运行
    try:
        for p in mp.active_children():
            p.join()
    except KeyboardInterrupt:
        print("Stopping all camera processes")
        for p in mp.active_children():
            p.terminate()

客户端调用

import ImageAcquisition as ia

# 直接调用run启动,无需写if判断
ia.run(["cam1", "cam2"])

优缺点

  • 优点:客户端代码极简,模块完全封装进程管理逻辑;子进程启动后直接退出,不会执行客户端脚本的顶级代码。
  • 缺点:若客户端脚本存在顶级执行代码(如print("Hello")),子进程启动时会先执行该代码再退出,需提示客户端将所有业务逻辑移至主进程执行链中。

方案2:提供主函数装饰器

通过装饰器标记客户端的主逻辑函数,仅主进程执行该函数,子进程调用时直接返回。

模块实现(ImageAcquisition.py)

import multiprocessing as mp
import functools
from typing import Callable, List

def _camera_worker(cam_id: str):
    # 相机采集逻辑同方案1
    pass

def Initialize(*cam_ids: str):
    # 初始化相机进程同方案1
    pass

def main(func: Callable) -> Callable:
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        if mp.current_process().name == 'MainProcess':
            return func(*args, **kwargs)
        return
    return wrapper

客户端调用

import ImageAcquisition as ia

# 用模块提供的装饰器标记主函数
@ia.main
def my_application():
    ia.Initialize("cam1", "cam2")
    # 其他业务逻辑
    print("Main application running")

# 直接调用主函数
my_application()

优缺点

  • 优点:客户端只需添加装饰器,比手动写if __name__ == '__main__'更简洁;子进程调用主函数时直接返回,不会执行内部逻辑。
  • 缺点:客户端仍需将业务逻辑封装在函数中,无法完全避免编写额外代码,但成本远低于手动加判断。

方案3:Unix环境下使用fork启动方式(仅适用于Linux/macOS)

在Unix系统中,multiprocessing默认使用fork启动方式,子进程会继承父进程的内存空间,不会重新导入模块,因此无需if __name__ == '__main__'判断。

模块实现(ImageAcquisition.py)

import multiprocessing as mp
import os

# 强制使用fork启动方式(仅Unix支持)
mp.set_start_method('fork')

def _camera_worker(cam_id: str):
    pass

def Initialize(*cam_ids: str):
    processes = []
    for cam in cam_ids:
        p = mp.Process(target=_camera_worker, args=(cam,))
        processes.append(p)
        p.start()
    return processes

客户端调用

import ImageAcquisition as ia

# 直接调用Initialize,无需任何判断
ia.Initialize("cam1", "cam2")

优缺点

  • 优点:客户端代码完全无额外判断,模块自包含性最强;进程启动速度快,无模块重新导入开销。
  • 缺点:仅支持Unix系统(Linux/macOS),Windows下无法使用;fork方式可能存在资源继承问题(如文件句柄、网络连接),需确保相机驱动兼容fork模式。

方案对比与推荐

  • 若需跨平台兼容,方案1或方案2是最优选择,其中方案1更适合客户端逻辑简单的场景,方案2更适合客户端有复杂主逻辑的场景。
  • 若仅面向Unix环境部署,方案3是最简洁高效的选择,完全无需客户端额外代码。

内容的提问来源于stack exchange,提问作者A. Vieira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:46:00