pyinstaller打包后pool.apply_async不执行目标函数反而调用主函数求助
故障原因
Windows 平台下 Python multiprocessing 模块创建子进程默认使用 spawn 模式,子进程启动时会重新导入完整的主模块代码。使用 PyInstaller 等工具打包为 exe 后,子进程无法正常触发 __name__ == '__main__' 的保护逻辑,每次创建子进程都会重新执行主函数代码,叠加你配置的单实例文件锁限制,子进程启动后会直接报错退出,因此目标函数uninstall_software_sub不会被执行。
解决方案
步骤1:添加多进程打包兼容代码
在__name__ == '__main__'代码块的最开头调用multiprocessing.freeze_support(),该函数专门用于适配打包场景的多进程兼容,不会影响源码直接运行的效果。
修改后的主入口代码示例:
import multiprocessing # 其余原有导入保持不变 if __name__ == '__main__': # 新增该行,必须放在主入口所有代码最前面 multiprocessing.freeze_support() print("main function called") try: # 使用文件锁,限制单进程 parent_folder = "C:\\Program Files (x86)\\ctyun\\eCloudDeskDRT\\sdk" if not os.path.exists(parent_folder): os.makedirs(parent_folder) lock_file_name = 'eCloudDeskDRTSrv.lock' lock_file_path = os.path.join(parent_folder, lock_file_name) lock_file_fd = open(lock_file_path, 'w') portalocker.lock(lock_file_fd, portalocker.LOCK_EX | portalocker.LOCK_NB) lock_file_fd.writelines(str(os.getpid())) lock_file_fd.flush() except BaseException as e: print("CloudDeskDRTSrv.exe have another instance running.") sys.exit()
步骤2:补全进程池生命周期管理
你当前调用apply_async提交任务后没有等待子进程执行完成,如果主进程提前退出,子进程会被系统直接杀死,需要补充进程池的关闭和等待逻辑:
def uninstall_software(software_name, uninstall_callback): log_utils.get_logger().info("uninstall_software software_name=%s", software_name) uninstall_info = get_uninstall_software_info(software_name) uninstall_string = uninstall_info.uninstall_string uninstall_process_name = uninstall_process.get(software_name, None) log_utils.get_logger().info(os.getpid()) pool = Pool(1) log_utils.get_logger().info('apply_async') pool.apply_async(func=third_party_software_check.uninstall_software_sub, args=(software_name, uninstall_string, uninstall_process_name), callback=uninstall_callback) # 新增两行,关闭进程池并等待任务执行完成 pool.close() pool.join()
如果你的程序是常驻后台服务,不需要同步等待卸载任务完成,也可以不加pool.join(),但需要确保主进程在卸载任务执行完成前不会退出。
内容的提问来源于stack exchange,提问作者Rongjie Shao
相关产品推荐
相关产品推荐

