【问题标题】:What is the overhead cost for running a Python script via a shell command executed by C++?通过 C++ 执行的 shell 命令运行 Python 脚本的开销是多少?
【发布时间】:2020-11-10 03:47:04
【问题描述】:

我正在使用 Python 脚本来处理 C++ 程序的一部分,但处理过程非常缓慢。

我有一个运行 shell 命令和检索输出的基本功能:

std::string ShellCommand::RunShellCommand(std::string cmd) {
    char buffer[128];
    std::string Response = "";
    FILE* pipe = popen(cmd.c_str(), "r");
    while (!feof(pipe)) {
       // use buffer to read and add to result
       if (fgets(buffer, 128, pipe) != NULL)
          Response += buffer;
    }
    pclose(pipe);
    return Response;
}

我在循环中使用这个命令:

void loop(int data) {
    while (HashSize(HashGenerator(data)) > 25) {
        data += 1;
    }
}

HashSize() 获取字符串哈希并通过迭代每个字符来计算前导零,直到找到非零字符,计算总二进制零。 HashGenerator() 函数使用上面的通用 shell 命令函数来激活 python 脚本:

import hashlib
import sys

# Get the data from argv
Data = sys.argv[1]

# Generate the hash
Hash = hashlib.sha256()
Hash.update(Data)

# Output the generated hash
print(Hash.hexdigest())

很明显,脚本的数据取自 shell 命令。

这一切都很好,但速度很慢(数据在几个小时内从 0 增加到大约 ~18,000)。现在,我的实际实现有点复杂,但我怀疑对 Python 的系统调用是导致这里问题的原因。

这个过程的开销是多少?你同意这是我的问题所在吗?有什么方法可以加快这个过程吗?

我希望这个问题对其他人有用,所以我想避免过于具体的硬件;但是,我应该提一下,这是在 Raspberry Pi Zero W 上运行的,它不以打破计算记录而闻名。不过,我仍然希望它比这更快。

【问题讨论】:

  • 如果不通过popen(...) 运行,python 脚本通常需要多长时间?
  • @Ilian Zapryanov 我没有确切的数字,但它要快得多。如果我在 python 中循环,它的速度大约是 10 倍。
  • 您是多次运行脚本,还是只运行一次?每次调用popen()时,它都必须创建一个shell进程,它会解析命令行,启动一个新的python进程,它会解析脚本。
  • 你当然不能指望这个问题的答案是相同的,例如,无论硬件是 Raspberry PI 还是 128 核 Threadripper。配备 128GB DDR 内存。很明显,每个硬件上的数字完全不同,只有通过在您的硬件上进行基准测试才能获得对您的案例有用的答案。

标签: python c++ linux shell raspberry-pi


【解决方案1】:

开销如下:

  • popen() - 它创建一个管道(低开销)并启动一个 sh 进程(相对昂贵)
  • sh - 解析命令行(低开销)并启动 python 进程(相对昂贵)
  • python - 解析和编译 Python 脚本(有点贵)并执行脚本。

第 2 步和第 3 步与从终端手动运行 Python 脚本相同。

在循环中启动大量进程通常不是一个好主意。如果不能在 C++ 中进行计算,更好的方法是设置与 Python 进程的双向通信,向其发送输入,然后读取结果。不幸的是,这代码比较复杂,因为popen() 只能创建单向通信。

【讨论】:

  • 很棒的信息,谢谢分享。看来我计划实现相同的代码客户端以匹配服务器端是不值得的。我将尝试纯粹用 C++ 来完成。