pyinstaller冻结打包多进程程序的bug:无限创建进程直至系统崩溃

前面写过两篇相关的文章:

  • PyQt应用程序打包
  • Python自动按键

这两篇文章都没有提到下面的这个重要问题:

采用Pyinstaller冻结打包多进程程序时,必须非常小心。这个技术线在Windows上会有一个非常严重的Bug。直接运行打包后的程序会造成无限创建进程,直到系统崩溃。

问题描述

本文针对一个非常具体的场景,需求包括以下要素:

  • 需要用PyQt5设计GUI程序
  • 需要调用其他库完成后台计算,计算与GUI线程松耦合
  • 通过PyInstaller打包成独立可执行程序

多进程的使用

在Python的标准库中,multiprocessing模块提供了多进程的支持。

如果我们采取这个技术线,则通常采用计算进程的方式来实现。

无限循环的计算进程

def worker(iq, oq):while True:# get input from input queuedata = iq.get()# process dataresult = f(data) # put result to output queueoq.put(result)

这个是一个典型的单纯的数据处理的计算过程,f(data)是一个计算函数,iq是输入队列,oq是输出队列。这个函数的内部是一个死循环,不断地从输入队列中获取数据,然后处理数据,最后将结果放到输出队列中。函数的大部分时间预计在get()函数的阻塞(当队列中没有数据时)和f(data)的计算上。

主进程启动计算进程

import multiprocessingif __name__ == '__main__':input_q = multiprocessing.Queue()output_q = multiprocessing.Queue()multiprocessing.Process(target=worker, args=(input_q, output_q), daemon=True).start()    

这里的daemon=True表示这个进程是一个守护进程,当主进程结束时,这个进程也会结束;否则必须要等待这个进程结束后,才能结束主进程。如果不设置这里或者daemon=False,就需要在worker函数中设置一个退出条件。例如:

def worker(iq, oq):while True:# get input from input queuedata = iq.get()if data == 'EXIT':break# process dataresult = f(data) # put result to output queueoq.put(result)

这样,当主进程发送一个EXIT的数据时,计算进程就会退出。

数据共享

multiprocessing中,有两个机制可以实现进程中的数据共享:

  • Queue:进程间通信的队列
  • Pipe:进程间通信的管道

这两个机制中,Queue是比较高层次的,Pipe是比较底层的。所以后者的效率(也许)会更高。对于我们常规的应用,主要计算时间在上面的f(data),所以直接使用Queue就可以了。

PyInstaller和UPX

在交付Python应用时,通常的术语成为“冻结”(Frozen)。冻结的目的是将Python程序打包成一个独立的可执行文件,这个文件可以在没有Python解释器的环境中运行。

常见的冻结工具有:

  • PyInstaller
  • cx_Freeze

大概用得比较多的就是这两个,我使用前者更多一些。

这个工具的使用方法非常简单,只需要在命令行中输入:

pyinstaller your_script.py

这个命令会在当前目录下生成一个dist目录,里面包含了所有的依赖文件和可执行文件。

当然我们还可以设置一些选项,例如:

  • -D:生成一个目录,而不是一个单独的文件
  • -F:生成一个单独的文件

UPX压缩

当然,在生成可执行文件后,我们还可以使用UPX进行压缩。UPX是一个开源的可执行文件压缩工具,可以将可执行文件压缩到更小的体积。

  • UPX官网

通常在调用PyInstaller时,我们可以使用下面的命令:

pyinstaller -D your_script.py --upx-dir=upx-folder

这里,就设置了UPX的目录,当然,如果在当前的环境变量的PATH中有UPX,那么就不需要设置这个选项了。

可以用--no-upx来禁用UPX。

在常见(PyQt5)情况下,UPX还是能够提供超过50%的压缩率的。非常可观。

多进程与冻结的冲突

在Windows开发中,试图冻结一个上面的程序,不会有任何错误提示。

但是会带来一个非常严重的Bug。当客户运行冻结的exe时,程序会疯狂创建新的进程,直到系统崩溃。

请不要测试……必须直接关机。

这个问题的原因是,multiprocessing模块在Windows中使用spawn方法来创建新的进程。而在冻结程序中,没有python解释器,所以multiprocessing模块会调用我们冻结得到的exe,然后这个exe又会调用multiprocessing模块,然后……就会无限循环。

解决方案

在冻结多进程multiprocessing的程序时,我们需要在if __name__ == '__main__':中调用freeze_support()函数。

if __name__ == '__main__':multiprocessing.freeze_support()input_q = multiprocessing.Queue()output_q = multiprocessing.Queue()multiprocessing.Process(target=worker, args=(input_q, output_q), daemon=True).start()    

这个调用必须在任何其他的multiprocessing调用之前进行。这里就在if __name__ == '__main__':中调用。

一个表现良好的例子

界面

下面是一个表现良好的例子.

这个例子是一个简单的加法计算器,用户输入两个数,然后计算它们的和。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

后台的计算进程是一个无限循环的进程,不断地从输入队列中获取数据,然后计算,最后将结果放到输出队列中。这里的PyQt5部分采取了硬核布局(!)。

代码

import multiprocessing
import sysfrom PyQt5.QtWidgets import QApplication, QLineEdit, QListWidget, QPushButton
from PyQt5.QtWidgets import QMainWindow# process to calculate, data by Queue across processes
def calculate(input_queue_a: multiprocessing.Queue, output_queue_a: multiprocessing.Queue):while True:try:x, y = input_queue_a.get()result = x + youtput_queue_a.put({"x": x, "y": y, "result": result})except:continuedef tryParse(s, default_value=0.0):try:num = float(s)except ValueError:num = default_valuereturn num# Press the green button in the gutter to run the script.
if __name__ == '__main__':multiprocessing.freeze_support()input_queue = multiprocessing.Queue()output_queue = multiprocessing.Queue()multiprocessing.Process(target=calculate, daemon=True, args=(input_queue, output_queue)).start()# PyQt Windowapp = QApplication(sys.argv)window = QMainWindow()window.setWindowTitle('Multiprocessing')# add ui elements herenum1_input = QLineEdit(window)num1_input.move(20, 20)num1_input.resize(200, 30)num2_input = QLineEdit(window)num2_input.move(20, 60)num2_input.resize(200, 30)calculate_button = QPushButton('Calculate', window)calculate_button.move(20, 100)calculate_button.resize(200, 30)output_list = QListWidget(window)output_list.move(20, 140)output_list.resize(200, 200)def calculate():x = tryParse(num1_input.text() or 0.0)y = tryParse(num2_input.text() or 0.0)input_queue.put((x, y))try:xy_result = output_queue.get()output_list.addItem(f"{xy_result['x']} + {xy_result['y']} = {xy_result['result']}")except Exception as e:output_list.addItem(f"Error{e}")output_list.scrollToBottom()calculate_button.clicked.connect(calculate)num2_input.returnPressed.connect(calculate)num1_input.returnPressed.connect(calculate)window.resize(240, 360)# fix window size, set it to non-resizablewindow.setFixedSize(240, 360)window.show()# exit app when close windowsys.exit(app.exec_())

其他注意事项

程序充分考虑了用户输入的错误,当用户输入的不是数字时,会自动转换为0.0。当用户输入的是空字符串时,也会转换为0.0。

并且,按钮,输入框的回调函数都是一个函数。

值得注意的是,Python的multiprocessing.Queue是什么都能放,简直是头发安全的程序设计。这里,我们传出的数据是一个字典,包含了输入的两个数和计算的结果。通过重复输入的数据,我们更大程序的避免了计算进行和主进程的耦合。这又是一个典型面向头发安全的编程习惯。

打包

在打包之前,应该用pip安装pyinstaller。这个时候,我们可以使用下面的命令:

# 设置UPX目录
pyinstaller -D -w ./main.py -n addUpx -y --upx-dir=D:/Users/User/upx-4.2.4-win64# 不使用UPX
pyinstaller -D -w ./main.py -n addWithoutUpx --noupx -y

在我们注意了所有的事项后,我们就可以放心地交付我们的程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66475.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全-kail linux 网络配置(基础篇)

一、网络配置 1.查看网络IP地址, 我的kail:192.168.15.128 使用ifconfig查看kail网络连接情况,ip地址情况 又复制了一台kail计算机的IP地址。 再看一下windows本机:使用ipconfig进行查看: 再看一下虚拟机上的win7I…

uni app 写的 小游戏,文字拼图?文字拼写?不知道叫啥

从下方的偏旁部首中选在1--3个组成上面文章中的文字&#xff0c;完成的文字标红 不喜勿喷 《满江红》 其中用到了两个文件 strdata.json parameters.json 这两个文件太大 放到资源中了 资源文件 <template><view class"wenzi_page_main"><view c…

分享几个高清无水印国外视频素材网站

在数字内容创作日益盛行的今天&#xff0c;高质量的视频素材成为了视频制作、广告创意和多媒体项目中不可或缺的元素。对于追求专业水准的创作者而言&#xff0c;高清、无水印的视频素材是确保作品质量的基石。以下将分享几个优质的视频素材网站&#xff0c;为您的创作之路提供…

【LLM】大语言模型基础知识及主要类别架构

文章目录 LLM大语言模型1.LLM基础知识1.1大模型介绍:1.2语言模型1.21n-gram语言模型1.22神经网络语言模型1.23基于Transformer的预训练语言模型1.24大语言模型 1.3模型评估指标1.31 BLEU1.32 Rouge指标1.33 困惑度PPL 2.LLM主要类别架构2.1 自编码模型2.2 自回归模型2.3 Encode…

剖析 Claim-Check 模式:以小传大,赋能分布式系统与微服务

1. 前言 1.1 写作背景与目的 在当今分布式系统与微服务架构盛行的时代&#xff0c;服务间的消息传递与数据交换越来越频繁。传统的消息传输在面对海量数据时&#xff0c;往往会遇到以下痛点&#xff1a; 消息体过大&#xff1a;直接通过消息队列或服务间接口发送大体量数据&…

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是&#xff1a;建立一套监控平台&#xff0c;比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台&#xff0c;就可以接入系统异常的监控和报警&#xff0c;可以设置当系统出现OOM异常&…

Idea(中文版) 项目结构/基本设置/设计背景

目录 1. Idea 项目结构 1.1 新建项目 1.2 新建项目的模块 1.3 新建项目模块的包 1.4 新建项目模块包的类 2. 基本设置 2.1 设置主题 2.2 设置字体 2.3 设置注释 2.4 自动导包 2.5 忽略大小写 2.6 设置背景图片 3. 项目与模块操作 3.1 修改类名 3.2 关闭项目 1. I…

liunx 中编写 springboot 服务停止时定时检查重启脚本

当服务内存溢出或其他一些原因&#xff0c;导致程序停止运行&#xff0c;服务不可用&#xff0c;为了服务能够及时自动重启&#xff0c;记录一下操作过程&#xff01; 首先编写自动重启的脚本指令&#xff0c;脚本在服务器上编写的&#xff0c;最后不要写好txt文件&#xff0c;…

CV-LLM经典论文解读|VTimeLLM: Empower LLM to Grasp Video MomentsVTimeLLM:赋能大语言模型理解视频片段

论文标题 VTimeLLM: Empower LLM to Grasp Video Moments VTimeLLM&#xff1a;赋能大语言模型理解视频片段 论文链接&#xff1a; VTimeLLM: Empower LLM to Grasp Video Moments论文下载 论文作者 Bin Huang, Xin Wang, Hong Chen, Zihan Song, Wenwu Zhu (Tsinghua Un…

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

ceph文件系统

ceph文件系统&#xff1a;高度可扩展&#xff0c;分布式的存储文件系统&#xff0c;旨在提高性能&#xff0c;高可靠性和高可用的对 象存储&#xff0c;块存储&#xff0c;文件系统的存储。使用分布式的算法保证数据的高可用和一致性。 ceph的组件 1、MON&#xff1a;ceph m…

Django的runserver

当年执行 python manage runserver命令时 1. 先执行 runserver 中的 handle方法 2. 执行 self.run()方法 3. 执行 self.inner_run() 3.1 inner_run 下 run方法的封装 3.1.1 接着看 handle 怎么来的 封装了一个方法 接着找返回函数 3.1.2在 basehttp 下 3.1.3 get_wsgi_appl…

开源AI智能名片2+1链动模式S2B2C商城小程序在商业流量获取中的应用研究

摘要&#xff1a; 随着互联网技术的迅猛发展&#xff0c;商业流量的获取已成为企业市场竞争中的关键环节。传统意义上的“客流量”在互联网语境下被赋予了新的内涵&#xff0c;即“商业流量”&#xff0c;其本质依然指向用户。在当前线上线下融合的商业环境中&#xff0c;流量…

(leetcode算法题)76. 最小覆盖子串

以s "ADOBECODEBANC", t "ABC"为例&#xff0c;进行如下演示 对于上图的说明&#xff1a; 1. 上面八个状态是在从左往右滑动窗口时&#xff0c;每发现一个窗口满足以下条件就进行状态暂停 条件&#xff1a;s[l, r] 覆盖了 t 这个字符串 2. 只有出窗口之…

2025-01-07 Unity 使用 Tip3 —— 游戏保存数据到 Application.persistentDataPath 不生效解决方案更新

文章目录 1 问题描述2 老版解决方案&#xff08;测试可行&#xff09;2.1 创建 js 脚本2.2 添加 js 引用 3 新版解决方案&#xff08;测试不可行&#xff09;4 实际问题 ​ WebGL 平台限制了文件访问系统&#xff0c;在 Unity 以前版本中&#xff0c;开发者想要在 WebGL 上保存…

IDEA的常用设置

目录 一、显示顶部工具栏 二、设置编辑区字体按住鼠标滚轮变大变小&#xff08;看需要设置&#xff09; 三、设置自动导包和优化导入的包&#xff08;有的时候还是需要手动导包&#xff09; 四、设置导入同一个包下的类&#xff0c;超过指定个数的时候&#xff0c;合并为*&a…

Anthropic 的人工智能 Claude 表现优于 ChatGPT

在人工智能领域&#xff0c;竞争一直激烈&#xff0c;尤其是在自然语言处理&#xff08;NLP&#xff09;技术的发展中&#xff0c;多个公司都在争夺市场的主导地位。OpenAI的ChatGPT和Anthropic的Claude是目前最具影响力的两款对话型AI产品&#xff0c;它们都能够理解并生成自然…

锂电池剩余寿命预测 | 基于BiLSTM-Attention的锂电池剩余寿命预测,附锂电池最新文章汇集

锂电池剩余寿命预测 | 基于BiLSTM-Attention的锂电池剩余寿命预测&#xff0c;附锂电池最新文章汇集 目录 锂电池剩余寿命预测 | 基于BiLSTM-Attention的锂电池剩余寿命预测&#xff0c;附锂电池最新文章汇集预测效果基本描述程序设计参考资料 预测效果 基本描述 锂电池剩余寿…

代码随想录算法训练营第四十天 | 股票问题

LeetCode 121.买卖股票的最佳时机&#xff1a; 文章链接 题目链接&#xff1a;121.买卖股票的最佳时机 思路 方法1&#xff1a;暴力 看到题目最直接的想法是双层遍历求最大区间差 class Solution:def maxProfit(self, prices):if len(prices) < 1:return 0result 0for…