如何使用freeze_support从冻结的sys.argv调用中获取真正的参数列表



我有一个独特的问题-我的解决方案,我希望使用pyinstaller进行打包,在启动时基于sys.argv进行一些JIT。在Windows上将multiprocessingfreeze_support一起使用时,多处理需要传入不同的参数来初始化新进程。当调用目标函数时,最终会设置原始的sys.argv。如何在调用目标函数之前获得原始的sys.argv?

import sys
import multiprocessing
print('ArgV:', sys.argv)

def print_argv():
print(sys.argv)
if __name__ == '__main__':
multiprocessing.freeze_support()
print_argv()
p = multiprocessing.Process(target=print_argv)
p.start()
p.join()

当使用pyinstaller打包并使用--hello=True运行时,会产生:

ArgV: ['scratch.exe', '--hello=True']
['scratch.exe', '--hello=True']
ArgV: ['scratch.exe', '--multiprocessing-fork', 'parent_pid=16096', 'pipe_handle=380']
['scratch.exe', '--hello=True']

我想要一些神奇的代码,当sys.argv设置为--multiprocessing-fork...时,它会给我原始的sys.argv,即--hello=True

我从未广泛使用过冻结可执行文件,但我有几个想法。。。

看看multiprocessing.spawn._main(),在原始sys.argv上的复制发生在这里:

preparation_data = reduction.pickle.load(from_parent)
prepare(preparation_data)

如果重写Process.__new__,则应该能够在_bootstrap(最终在进程对象上调用run(之前运行代码,但要在收到sys.argv之后运行。

import sys
import multiprocessing
print('ArgV:', sys.argv)
def print_argv():
print(sys.argv)

class myProcess(multiprocessing.Process):
def __new__(cls, *args, **kwargs):
if __name__ == "__mp_main__":
print("hook", sys.argv)
instance = super(myProcess, cls).__new__(cls) 
instance.__init__(*args, **kwargs)
return instance
if __name__ == '__main__':
multiprocessing.freeze_support()
print_argv()
p = myProcess(target=print_argv)
p.start()
p.join()

另一个想法是通过覆盖__getstate____setstate__来挂接unpickle进程。

class myProcess(multiprocessing.Process):

def __getstate__(self):
return self.__dict__.copy()

def __setstate__(self, state):
print("hook", sys.argv)
self.__dict__.update(state)

最后,您可以挂接pickle查找要取消拾取的自定义类时生成的审核事件:

class myProcess(multiprocessing.Process):
pass
def hook(event_name, args):
if "pickle.find_class" in event_name:
if args[1] == myProcess.__name__:
print("hook", sys.argv)

sys.addaudithook(hook)

所有这些在加载新流程的过程中大致同时发生,我不能说哪一个最健壮。。。

最新更新