洛基的城堡

Python学习手记

使用pyinstaller打包的坑

项目中用到pyinstaller将python打成.exe可执行文件:

结果发现如下问题:

由于需要获取命令执行的状态值及返回信息,因此放弃了os.system,os.popen等,commands.getstatusoutput在windows平台也不能使用,因此选择subprocess模块。 os.system还有个坑,当cmd有多个引号时,会解析cmd失败。

1.subprocess.Popen调用报异常:

当使用pyinstaller打成.exe文件安装后

使用p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

报WindowsError:[Error 6]异常

单独使用subprocess.check_output(cmd)同样报此异常。

奇怪的是,直接用源码测试执行时系统完全没有任何问题。

后来才发现,当使用pyinstaller打包时,Popen应该如下初始化:

p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

msg = ''

for line in p.stdout.readlines():

msg += line

status = p.wait()

这样就可以轻松获取指令执行返回的状态值和信息了。

2.Multiprocessing

系统在linux下多进程正常执行,但用pyinstaller打包后在windows下,pool.apply_async(...)多进程启动没有任何反应。在网上找了很久发现:

代码中直接使用标准库中的multiprocessing.Process和multiprocessing.Pool,在打包成可执行程序后会创建进程失败。对于pyinstaller的one-directory模式,只要再程序的最开始调用multiprocessing. freeze_support()就可以了,但对于one-file模式,还需要使用下面修改后的Process和Pool。

import multiprocessing.forking

import multiprocessing.pool

import os

import sys

class _Popen(multiprocessing.forking.Popen):

def __init__(self, *args, **kw):

if hasattr(sys, 'frozen'):

os.putenv('_MEIPASS2', sys._MEIPASS + os.sep)

try:

super(_Popen, self).__init__(*args, **kw)

finally:

if hasattr(sys, 'frozen'):

if hasattr(os, 'unsetenv'):

os.unsetenv('_MEIPASS2')

else:

os.putenv('_MEIPASS2', '')

class Process(multiprocessing.Process):

_Popen = _Popen

class Pool(multiprocessing.pool):

Process = Process

3.此外,pyinstaller只支持ascii,打包后可执行文件路径不能有中文。

参考文章:

https://stackoverflow.com/questions/24944558/pyinstaller-built-windows-exe-fails-with-multiprocessing

https://www.aichengxu.com/view/29937


转载自:https://blog.sina.com.cn/s/blog_b1e0a3740102vpeb.html


评论
热度(2)

© 洛基的城堡 | Powered by LOFTER