鱼C论坛

 找回密码
 立即注册
查看: 1194|回复: 6

[已解决]求助,pyinstaller打包以后和pycharm运行的不一样

[复制链接]
发表于 2023-7-12 10:27:03 | 显示全部楼层 |阅读模式
30鱼币
学习了多进程,想试一下。代码如下,在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()
最佳答案
2023-7-12 10:27:04
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
2.jpg
1.jpg

最佳答案

查看完整内容

打包成exe后出现多个窗口的问题是由于多进程的特性引起的。在Windows系统上,当使用PyInstaller将多进程的Python脚本打包成exe时,由于进程间通信的机制不同,可能会出现多个窗口弹出的情况。 解决这个问题的方法是在创建进程之前判断当前进程是否为主进程,然后再创建子进程。可以使用if __name__ == '__main__':来判断当前进程是否为主进程,只在主进程中创建子进程。 修改代码如下: 在打包之前,将multiprocessin ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-12 10:27:04 | 显示全部楼层    本楼为最佳答案   
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
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-12 10:27:17 | 显示全部楼层
在使用 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/
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-12 10:51:13 | 显示全部楼层
不要用win7虚拟机吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-7-12 10:56:01 | 显示全部楼层

是因为物理机运行以后会死机,我才在虚拟机里面运行截图
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-7-12 11:12:25 | 显示全部楼层
歌者文明清理员 发表于 2023-7-12 10:27
打包成exe后出现多个窗口的问题是由于多进程的特性引起的。在Windows系统上,当使用PyInstaller将多进程 ...

谢谢!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-12 11:12:32 | 显示全部楼层
感谢楼主最佳之恩!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-22 13:40

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表