使用 PyInstaller 可执行程序卡在循环中的进程

Posted

技术标签:

【中文标题】使用 PyInstaller 可执行程序卡在循环中的进程【英文标题】:Processes stuck in loop with PyInstaller-executable 【发布时间】:2019-01-06 19:24:02 【问题描述】:

Python v3.5,Windows 10

我正在使用多个进程并尝试捕获用户输入。搜索我看到的所有内容时,在将input() 与多个进程一起使用时会发生奇怪的事情。经过 8 小时以上的尝试,我没有实施任何方法,我很肯定我做错了,但我终其一生都无法弄清楚。

以下是演示该问题的非常精简的程序。现在,当我在 PyCharm 中运行这个程序时它可以正常工作,但是当我使用 pyinstaller 创建单个可执行文件时它会失败。程序一直卡在一个循环中,要求用户输入如下所示的内容:。

我很确定这与 Windows 如何从我阅读的内容中获取标准输入有关。我也尝试将用户输入变量作为Queue() 项传递给函数,但同样的问题。我读到您应该将input() 放在主要的python 进程中,所以我在if __name__ = '__main__': 下这样做了

from multiprocessing import Process
import time


def func_1(duration_1):
    while duration_1 >= 0:
        time.sleep(1)
        print('Duration_1: %d %s' % (duration_1, 's'))
        duration_1 -= 1


def func_2(duration_2):
    while duration_2 >= 0:
        time.sleep(1)
        print('Duration_2: %d %s' % (duration_2, 's'))
        duration_2 -= 1


if __name__ == '__main__':

    # func_1 user input
    while True:
        duration_1 = input('Enter a positive integer.')
        if duration_1.isdigit():
            duration_1 = int(duration_1)
            break
        else:
            print('**Only positive integers accepted**')
            continue

    # func_2 user input
    while True:
        duration_2 = input('Enter a positive integer.')
        if duration_2.isdigit():
            duration_2 = int(duration_2)
            break
        else:
            print('**Only positive integers accepted**')
            continue

    p1 = Process(target=func_1, args=(duration_1,))
    p2 = Process(target=func_2, args=(duration_2,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

【问题讨论】:

【参考方案1】:

当您使用 PyInstaller 生成 Windows 可执行文件时,您需要使用 multiprocessing.freeze_support()

直接出docs:

multiprocessing.freeze_support()

添加对使用多处理的程序被冻结以生成 Windows 可执行文件时的支持。 (已使用 py2exe、PyInstaller 和 cx_Freeze 测试。)

需要在主模块的 if name == 'ma​​in' 行之后直接调用此函数。例如:

from multiprocessing import Process, freeze_support

def f():
    print('hello world!')

if __name__ == '__main__':
    freeze_support()
    Process(target=f).start()

如果 freeze_support() 行被省略,那么尝试运行冻结的可执行文件将引发 RuntimeError。

在除 Windows 之外的任何操作系统上调用时,调用 freeze_support() 均无效。另外,如果模块在Windows上被Python解释器正常运行(程序没有被冻结),则freeze_support()没有任何作用。

在您的示例中,您还应该解决不必要的代码重复问题。

【讨论】:

什么是重复代码?我想要两个用于用户输入的while循环,因为如果第二个用户输入没有正确输入,我不希望它每次都在开始时重新开始。 @probat func1func2 是相同的,您只是使用其他名称,并且可以通过例如为此添加另一个参数来动态更改打印的文本。您也可以将 while 循环放入一个函数中,然后调用两次。 我的真实脚本中的函数中确实有用于用户输入的 while 循环。我只是试着让这个尽可能简单,直接在这里问这个问题。感谢您的帮助,我真的很感激。多处理模块有很多文档,我错过了。

以上是关于使用 PyInstaller 可执行程序卡在循环中的进程的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的 kivy 应用程序(Pyinstaller)获取 Windows 可执行文件?

导出单个 .exe 时,PyInstaller 卡在“正在构建 PKG ...”

使用pyinstaller制作包含Oracle数据库的可执行程序

使用pyinstaller打包.py程序

Pyinstaller 可执行文件不起作用

用Pyinstaller生成可执行文件