使用Python multiprocessing.Process运行虚拟环境

3
我正在使用virtualenv运行程序。但是这里生成的multiprocessing.Process默认使用系统python。我该如何强制其使用virtualenv python?
import os
from multiprocessing import Process

def function1():
    # do_something_here
    p = Process(func2(), args=(param,))
    p.start()
    return something

def func2(param):
    os.system("which python")

这里打印的是 "/usr/bin/python"。但我需要使用 virtualenv 中的 python。

你确定父进程是使用 virtualenv 的 Python 启动的吗? - georgexsh
@georgexsh 是的,实际上这些函数是 Flask 应用程序的一部分。 - Kumaran
1
我测试了上述程序的修复版本(例如,您没有将func2()作为进程参数,而是使用了func2,并进行了其他一些修复),它确实返回了virtualenv版本。在生成进程之前,请尝试在主程序中添加os.system("which python"),看看会发生什么。 - Hannu
@georgexsh 我是使用sudo运行它的。默认情况下,如果您使用sudo,则会使用系统Python。因此,我使用“sudo venv/bin/python main.py”来运行程序。即使我在这里使用venv的python,它仍然返回“/usr/bin/python”作为“os.system('which python')”。我不理解这种行为。 - Kumaran
@Kumaran PYTHONPATH/PATH/sudo 这些都与你的问题无关,我已经相应地更新了我的答案。 - georgexsh
显示剩余2条评论
2个回答

3
使用sudo venv/bin/python命令,您可以直接使用虚拟环境中的Python可执行文件有效激活虚拟环境multiprocessing.Process使用fork()生成子进程,而不使用exec(),它使用与父进程完全相同的Python可执行文件。
您可以通过以下方式确认正在使用的Python可执行文件:
>>> import sys
>>> print(sys.executable)
/Users/georgexsh/workspace/tmp/venv/bin/python
>>> print(sys.exec_prefix)
/Users/georgexsh/workspace/tmp/venv/bin/..

不要使用which来确定Python可执行文件的路径。作为Bash命令,which会搜索$PATH中的每个元素,查找包含名为“python”的可执行文件的目录。由于您直接使用virtualenv的python,而不是先运行其shell激活脚本,因此$PATH没有得到虚拟环境的修补,因此,Shell命令which python将输出系统Python可执行文件的路径。
实际上,在Python层面上,$PATH是无关紧要的,修补$PATH只是为了方便在Bash层面上调用虚拟环境路径中的Python可执行文件,而不必键入完整路径。最重要的是调用哪个Python可执行文件,而不是如何调用它。

这是正确的。我试过了。"sys.executable"打印venv的Python路径,但"which python"打印系统Python。谢谢@georgexsh - Kumaran

1
您的问题在这里(复制了您的评论):
@georgexsh我使用sudo运行它。默认情况下,如果您使用sudo,则会使用系统Python。因此,我使用“sudo venv / bin / python main.py”来运行程序。即使我在这里使用venv的python,它也会返回“/ usr / bin / python”用于“os.system('which python')”。我不明白这种行为。
基本上,您在这里解释的是虚拟环境未激活的情况。
当您激活虚拟环境(. venv / bin / activate)时,激活脚本将更改您的环境,以便您的PYTHONPATH正确,并且Python可执行文件首先在虚拟环境目录中搜索并找到。这就是virtualenv的作用。
仅通过从虚拟环境目录执行Python二进制文件,您的环境未设置为虚拟环境,因此任何后续对Python的调用都使用默认路径-因为虚拟环境不存在以覆盖它。
当您执行sudo时,会创建一个新的进程/ shell,并且它不会继承您的虚拟环境。您可能能够使用sudo -E来传递环境变量,但这取决于您的sudo。在每个环境中都应该能够正常工作的可靠版本是执行一个shell,首先激活virtualenv,然后执行您的脚本。类似于这样的内容:
sudo -- bash  -c ". /home/test/mytest/bin/activate; which python"

这个命令会以root身份执行bash shell,然后激活虚拟环境,并告诉你使用的python版本。只需用你的虚拟环境路径修改上述命令,它甚至可能起作用。
如果你的系统是共享的,请记住从安全角度允许普通用户执行此操作是非常糟糕的。如果你为普通用户创建了无密码sudo,他们将可以轻松获得root权限。如果这是你自己的系统,而且要求知道root密码,那么就没有关系了。

PYTHONPATH 在这里不起作用,而且 virtualenv 在此处是 激活 的,Process 也使用虚拟环境的 Python,你的其他说法也是完全错误的... - georgexsh
正如注释所述,OP 可能最初处于 virtualenv 活动状态,但随后他使用 sudo 执行 Python 和脚本,这将用他或系统的默认值替换 venv PATH。 - Hannu
通过在虚拟环境中使用Python可执行文件,sudo venv/bin/python 有效地 激活了虚拟环境。 - georgexsh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接