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

How can I get the real argument list from a frozen sys.argv call using freeze_support?

我有一个独特的问题 - 我的解决方案,我希望使用 pyinstaller 打包,在启动时 JIT 一些基于 sys.argv 的东西。当您在 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),但在 [=收到 15=]。

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 以取消 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)

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