求助,pyinstaller打包以后和pycharm运行的不一样
学习了多进程,想试一下。代码如下,在pycharm运行,会生成一个窗口,其他进程计算square。运行pyinstaller -F -w main.py打包以后成exe以后,运行会弹出很多个tk窗口,导致系统卡死。请教一下各位大佬,这是什么问题。该如何解决
# cython: language_level=3
# -*- coding:utf-8 -*-
import sys
import tkinter as tk
import time
import ntplib
import os
import multiprocessing
# 创建多进程要跑的方法,while循环
def square(i):
while True:
print(i*i*i*i*i*i*i)
# time.sleep(5)
def start():
cpuNum = multiprocessing.cpu_count()
print(cpuNum)
for i in range(cpuNum):
p = multiprocessing.Process(target=square, args=(i,))
p.daemon = True
p.start()
print('CPU number:' + str(multiprocessing.cpu_count()))
for p in multiprocessing.active_children():
print('Child process name: ' + p.name + ' id: ' + str(p.pid))
loginWindow = tk.Tk()
loginWindow.title('test')
screenWidthLogin = loginWindow.winfo_screenwidth()
screenHeightLogin = loginWindow.winfo_screenheight()
loginWindow.geometry('400x260+{}+{}'.format((screenWidthLogin - 400) // 2, (screenHeightLogin - 260) // 2))
loginWindow.resizable(False, False)
loginWindow.config(bg='pink')
loginFrame = tk.Frame(loginWindow, relief='sunken')
loginFrame.place(relx=0.5, rely=0.5, relheight=0.985, relwidth=0.985, anchor='center')
# 设置登录窗口标签属性
loginLabelUser = tk.Label(loginFrame, text='用户名', width=5, height=1)
loginLabelUser.place(relx=0.27, rely=0.345)
loginLabelPassword = tk.Label(loginFrame, text='密 码', width=5, height=1)
loginLabelPassword.place(relx=0.27, rely=0.555)
loginEntryUser = tk.Entry(loginFrame, width=15)
loginEntryUser.place(relx=0.44, rely=0.345)
loginEntryPassword = tk.Entry(loginFrame, show='*', width=15)
loginEntryPassword.place(relx=0.44, rely=0.555)
loginButtonLogin = tk.Button(loginFrame, text='登录', width=15, height=1)
loginButtonLogin.place(relx=0.2, rely=0.8)
loginButtonExit = tk.Button(loginFrame, text='退出', width=15, height=1, command=loginWindow.destroy)
loginButtonExit.place(relx=0.5, rely=0.8)
loginWindow.mainloop()
sys.exit()
if __name__ == '__main__':
while True:
try:
c = ntplib.NTPClient()
response = c.request('ntp2.aliyun.com')
ts = response.tx_time
_date = time.strftime('%Y-%m-%d', time.localtime(ts))
_time = time.strftime('%X', time.localtime(ts))
# 设置本机系统时间
os.system('date {} && time {}'.format(_date, _time))
break
except Exception as time_out:
print('同步超时', time_out)
continue
start()
kerln888 发表于 2023-7-12 10:56
是因为物理机运行以后会死机,我才在虚拟机里面运行截图
打包成exe后出现多个窗口的问题是由于多进程的特性引起的。在Windows系统上,当使用PyInstaller将多进程的Python脚本打包成exe时,由于进程间通信的机制不同,可能会出现多个窗口弹出的情况。
解决这个问题的方法是在创建进程之前判断当前进程是否为主进程,然后再创建子进程。可以使用if __name__ == '__main__':来判断当前进程是否为主进程,只在主进程中创建子进程。
修改代码如下:
# cython: language_level=3
# -*- coding:utf-8 -*-
import sys
import tkinter as tk
import time
import ntplib
import os
import multiprocessing
# 创建多进程要跑的方法,while循环
def square(i):
while True:
print(i*i*i*i*i*i*i)
# time.sleep(5)
def start():
cpuNum = multiprocessing.cpu_count()
print(cpuNum)
for i in range(cpuNum):
p = multiprocessing.Process(target=square, args=(i,))
p.daemon = True
p.start()
print('CPU number:' + str(multiprocessing.cpu_count()))
for p in multiprocessing.active_children():
print('Child process name: ' + p.name + ' id: ' + str(p.pid))
loginWindow = tk.Tk()
loginWindow.title('test')
screenWidthLogin = loginWindow.winfo_screenwidth()
screenHeightLogin = loginWindow.winfo_screenheight()
loginWindow.geometry('400x260+{}+{}'.format((screenWidthLogin - 400) // 2, (screenHeightLogin - 260) // 2))
loginWindow.resizable(False, False)
loginWindow.config(bg='pink')
loginFrame = tk.Frame(loginWindow, relief='sunken')
loginFrame.place(relx=0.5, rely=0.5, relheight=0.985, relwidth=0.985, anchor='center')
# 设置登录窗口标签属性
loginLabelUser = tk.Label(loginFrame, text='用户名', width=5, height=1)
loginLabelUser.place(relx=0.27, rely=0.345)
loginLabelPassword = tk.Label(loginFrame, text='密 码', width=5, height=1)
loginLabelPassword.place(relx=0.27, rely=0.555)
loginEntryUser = tk.Entry(loginFrame, width=15)
loginEntryUser.place(relx=0.44, rely=0.345)
loginEntryPassword = tk.Entry(loginFrame, show='*', width=15)
loginEntryPassword.place(relx=0.44, rely=0.555)
loginButtonLogin = tk.Button(loginFrame, text='登录', width=15, height=1)
loginButtonLogin.place(relx=0.2, rely=0.8)
loginButtonExit = tk.Button(loginFrame, text='退出', width=15, height=1, command=loginWindow.destroy)
loginButtonExit.place(relx=0.5, rely=0.8)
loginWindow.mainloop()
sys.exit()
if __name__ == '__main__':
if getattr(sys, 'frozen', False):
multiprocessing.freeze_support()
while True:
try:
c = ntplib.NTPClient()
response = c.request('ntp2.aliyun.com')
ts = response.tx_time
_date = time.strftime('%Y-%m-%d', time.localtime(ts))
_time = time.strftime('%X', time.localtime(ts))
# 设置本机系统时间
os.system('date {} && time {}'.format(_date, _time))
break
except Exception as time_out:
print('同步超时', time_out)
continue
start()
在打包之前,将multiprocessing.freeze_support()代码添加到if __name__ == '__main__':的判断中,这可以确保在Windows系统上运行exe文件时能正确处理多进程。
我修改了你提供的代码,主要是在启动多进程之前添加了multiprocessing.freeze_support()代码,并在主进程中创建了子进程。这样可以解决在Windows系统上使用PyInstaller打包成exe后出现多个窗口的问题。同时,将整个代码片段放置在if __name__ == '__main__':判断中,确保只有在直接运行脚本时才执行相关的代码,而在打包成exe后不执行这部分代码。
参考:https://fishc.com.cn/thread-226709-1-1.html 在使用 PyInstaller 打包后,程序的行为可能与在 PyCharm 中运行时不一样的原因是,在打包过程中可能会有一些与 GUI 相关的库或设置没有正确处理。
在你的代码中,你使用了 tkinter 创建了一个窗口。尝试将以下几行代码放到 if __name__ == '__main__': 的条件语句中:
loginWindow = tk.Tk()
# ...
loginWindow.mainloop()
然后,重新使用 PyInstaller 打包并运行生成的可执行文件,看看是否仍然会弹出多个窗口。这样做可以确保只有主进程创建并显示窗口。
如果问题仍然存在,你可以尝试使用 PyInstaller 的一些选项来调整打包过程的行为。例如,可以尝试使用 --noconsole 选项来禁用控制台窗口,或者使用 --onefile 选项生成单个可执行文件而不是文件夹。
例如,运行以下命令进行打包:
pyinstaller --onefile -w main.py
请注意,PyInstaller 的使用方法可能因版本而异,以上命令仅提供一种示范,具体命令参数可根据实际情况进行调整。
如果问题仍然存在,请尝试从 PyInstaller 的官方文档中查找其他解决方案:https://pyinstaller.readthedocs.io/ 不要用win7虚拟机吧 歌者文明清理员 发表于 2023-7-12 10:51
不要用win7虚拟机吧
是因为物理机运行以后会死机,我才在虚拟机里面运行截图 歌者文明清理员 发表于 2023-7-12 10:27
打包成exe后出现多个窗口的问题是由于多进程的特性引起的。在Windows系统上,当使用PyInstaller将多进程 ...
谢谢!!!! {:10_301:}感谢楼主最佳之恩!
页:
[1]