致命的Python错误:无法获取随机数以初始化Python。

7

致命的 Python 错误:无法获取随机数以初始化 Python。

环境为 Windows 10,VSC 15。

使用 CreateProcessA winapi 并传递 lpenvironment 变量来运行带有脚本的 Python。当 lpenvironment 为空时,它可以正常工作。但如果我设置环境变量 PATH 和 PYTHONPATH = "路径",并传递 LPSTR(env.c_Str()),则在运行时会抛出上述错误。Python 版本为 3.5.6。

有什么帮助吗?


更多详细信息:

  1. 我使用 CreateProcessA WINAPI 运行子进程 python.exe "C:\Program Files\endpoint\Python_ML\mlprocessor_server.py"。
  2. 我想要使用两个环境变量 "PYTHONPATH" 和 "PATH" 来运行子进程。
  3. PYTHONPATH="C:\Program Files\endpoint\Python";"C:\Program Files\endpoint\Python\Scripts";"C:\Program Files\endpoint\Python\include";"C:\Program Files\endpoint\Python\Lib";"C:\Program Files\endpoint\Python\libs";"C:\Program Files\endpoint\Python\Lib\site-packages";"C:\Program Files\endpoint\Python_ML"
  4. PATH="C:\Program Files\endpoint\Python";"C:\Program Files\endpoint\Python\Lib";"C:\Program Files\endpoint\Python\Scripts";"C:\Program Files\endpoint\Python\libs"

由于某种原因,CreateProcessA 中的第七个参数失败。如果此参数为空,则 python.exe 可以成功运行;否则,它会打印 "致命的 Python 错误:无法获取随机数以初始化 Python"。

我设置参数的方式如下:

std::string Base = Configuration::getBasePath();

std::string environPython = Base;
environPython.append("\\Python;");
environPython.append(Base);
environPython.append("\\Python\\Scripts;");
environPython.append(Base);
environPython.append("\\Python\\include;");
environPython.append(Base);
environPython.append("\\Python\\Lib;");
environPython.append(Base);
environPython.append("\\Python\\libs;");
environPython.append(Base);
environPython.append("\\Python\\Lib\\site-packages;");
environPython.append(Base);
environPython.append("\\Python\\_ML;");
environPython.push_back('\0');


std::string environPath = Base;
environPath.append("\\Python;");
environPath.append(Base);
environPath.append("\\Python\\Lib;");
environPath.append(Base);
environPath.append("\\Python\\Scripts;");
environPath.append(Base);
environPath.append("\\Python\\libs;");
environPath.push_back('\0');

std::string cmd = Base;
cmd.append("\\Python\\python.exe");
std::string params = "\"";
params.append(cmd);
params.append("\" \"");
params.append(Base);
params.append("\\Python\\_ML\\mlprocessor_server.py\"");

std::map env = {{"PYTHONPATH",environPython.data()},{"PATH",environPath.data()}};


这行代码创建了一个名为env的映射对象,其中包含两个键值对。第一个键值对的键是“PYTHONPATH”,值为environPython.data();第二个键值对的键是“PATH”,值为environPath.data()。
// example for generating block of strings
std::vector<char> envBlock;
std::for_each(env.begin(), env.end(),
    [&envBlock](const std::pair<std::string, std::string> & p) {
    std::copy(p.first.begin(), p.first.end(), std::back_inserter(envBlock));
    envBlock.push_back('=');
    std::copy(p.second.begin(), p.second.end(),   std::back_inserter(envBlock));
    envBlock.push_back('\0');
}
);
envBlock.push_back('\0');

// feed this into ::CreateProcess()
LPVOID lpEnvironment = (LPVOID)envBlock.data();

bool result = CreateProcessA(cmd.c_str(), (LPSTR)params.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, lpEnvironment, NULL, &info, &pi);

结果总是返回 true,python.exe 在任务管理器中未显示,并出现致命的 Python 错误:无法获取随机数以初始化 Python。

如果 lpEnvironment 为 NULL,则 python.exe 将在任务管理器中显示。


1
你的意思是将PYTHONPATH设置为字符串文字“paths”吗? - Gloweye
PYTHONPATH 应该设置为你的项目根目录。而 PATH 则应该设置为 /path/to/python。当你说 '= "paths"' 这个表达式时,你到底是什么意思? - DUDANF
我更新了这个问题,您能再审核一下吗? - Sunder Ganesan
请告诉我以上代码片段中有什么问题? - Sunder Ganesan
请求更新? - Sunder Ganesan
显示剩余2条评论
2个回答

9

调用 CreateProcessA 时,传递的环境变量中必须包括 SYSTEMROOT,否则在 python 初始化期间调用 Win32 API 函数 CryptAcquireContext 会失败。

当将 lpEnvironment 参数设置为 NULL 时,新进程将继承调用进程的环境变量,该进程已经定义了 SYSTEMROOT


3
为了举一个例子,说明在现实世界中如何在纯Python软件中很容易地触发它,有时候Python打开自身的实例来执行一些任务是很有用的,其中子任务需要设置特定的PYTHONPATH。通常情况下,在不那么挑剔的平台上(例如非Windows平台),可以像这样懒惰地完成:
import sys
from subprocess import Popen
p = Popen([sys.executable, '-c', 'print("hello world")'], env={
    'PYTHONPATH': '',  # set it to somewhere
})

然而,在Windows上这样做会导致以下令人困惑的失败:

Python 3.8.10 (...) [MSC v.1928 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> from subprocess import Popen
>>> p = Popen([sys.executable, '-c', 'print("hello world")'], env={
...     'PYTHONPATH': ''
... })
Fatal Python error: _Py_HashRandomization_Init: failed to get random numbers to initialize Python
Python runtime state: preinitialized

显然的解决方法是:克隆os.environ以确保SYSTEMROOT被放置到正确的位置,从而避免@Joe Savage答案中指出的问题,例如:
>>> import os
>>> env = os.environ.copy()
>>> env['PYTHONPATH'] = ''
>>> p = Popen([sys.executable, '-c', 'print("hello world")'], env=env)
hello world

这种修复方式需要的真实世界示例:


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