首页 > 编程问答 >为什么 process.communicate 会导致我的程序被终止?

为什么 process.communicate 会导致我的程序被终止?

时间:2024-07-26 11:47:57浏览次数:11  
标签:python c++ python-3.x subprocess python-3.8

我正在 python 中运行一个程序的一些代码,当我运行 c++ 时,我需要处理它的标准输入,例如 scanf 和 cin。我正在使用 subprocess.Popen 运行编译后的 C++ 程序。当我不提供任何标准输入时,我预计它会超时并引发异常,但我的程序立即结束并在控制台上打印 Killed 。 这是我的课程的一部分,我相信这已经足够了

    def run(
        self, args: List[str] = [], stdin: str = "", timeout: int = 30
    ) -> Tuple[int, str, str]:

        process = subprocess.Popen(
            [os.path.join(self.temp_file_folder, "build", self.target_file_name)]
            + args,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
        )

        try:
            stdout, stderr = process.communicate(input=stdin, timeout=timeout)
        except subprocess.TimeoutExpired as e:
            process.kill()
            raise RunTimeoutError(f"Expired in {timeout}s")

        return (process.returncode, stdout, stderr)

当我使用30s时,程序在运行process.communicate后直接退出并在控制台上打印 Killed 没有任何异常。但是当我使用 5s 时,它会像我预期的那样抛出异常。 我在没有任何标准输入的情况下调用我的函数。

当 timeout == 30 时输出如下:

Killed

当 timeout == 5 时输出如下:

Traceback (most recent call last):
  File "/home/jayzhu/projects/code-auto-comment/src/runner/__init__.py", line 161, in <module>
    res = runner.run(timeout=5)
  File "/home/jayzhu/projects/code-auto-comment/src/runner/__init__.py", line 124, in run
    raise RunTimeoutError(f"Expired in {timeout}s")
__main__.RunTimeoutError: Expired in 5s

这是我当时运行的 C++ 代码

#include <iostream>
#include <cmath>
#include <limits>
#include <iomanip>

int main()
{
    int N;
    double sum = 0;
    double product = 1;

    std::cout << "Please enter an integer  N between 1 and 50: ";
    std::cin >> N;

    while (std::cin.fail() || N < 1 || N > 50)
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\\n');
        std::cout << "Input error, please enter an integer N between 1 and 50: ";
        std::cin >> N;
    }

    std::cout << N << ":" << std::endl;
    for (int i = N - 1; i >= 0; i--)
    {
        int value = pow(2, i);
        sum += value;
        product *= value;
        std::cout << value << (i > 0 ? ", " : "\\n");
    }

    double geometric_mean = pow(product, 1.0 / N);
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "sum: " << sum << std::endl;
    std::cout << "avg: " << geometric_mean << std::endl;

    return 0;
}

I不太确定这是 c++ 代码的问题,还是我自己的代码的问题

我的环境是 python 3.8.10 Ubuntu 20.04.6 LTS


问题出在你的 C++ 代码和 process.communicate() 的交互上。以下是发生的情况:

  1. C++ 代码等待输入: 你的 C++ 代码使用 std::cin >> N; 来等待用户输入一个整数。

  2. process.communicate(input=stdin, timeout=timeout) 被调用: 你使用 process.communicate() 发送输入并等待进程完成。

  3. 死锁情况: 当你没有提供任何标准输入 ( stdin="" ) 时,就会出现问题。C++ 代码停滞,等待输入,而 process.communicate() 则在等待 C++ 代码完成,从而导致死锁。

  4. 超时差异:

  5. timeout=30 时, process.communicate() 会等待 30 秒,然后在进程仍在运行时被你的系统杀死,导致 "Killed" 消息。
  6. timeout=5 时, process.communicate() 会在 5 秒后超时,并引发你捕获到的 subprocess.TimeoutExpired 异常。

解决方案:

你有几种选择来解决这个问题:

1. 修改 C++ 代码:

  • 添加超时: 你可以修改 C++ 代码,使其在没有接收到输入的情况下超时。这可以通过使用多线程或非阻塞 I/O 来实现。

  • 默认值: 如果未提供输入,则使用默认值。

2. 在单独的线程中处理输入:

  • 创建一个单独的线程来处理与 C++ 进程的输入。
  • 使用 process.stdin.write() 发送输入。
  • 使用 process.stdout.readline() 或类似方法从进程读取输出。

3. 使用 pexpect 库(如果适用):

  • 如果你需要与交互式程序进行更复杂的交互, pexpect 库可以提供帮助。它允许你发送输入、预期模式,并根据需要做出响应。

示例(使用默认值修改 C++ 代码):

#include <iostream>
#include <cmath>
#include <limits>
#include <iomanip>

int main() {
    int N = 1; // 默认值

    std::cout << "请输入一个介于 1 和 50 之间的整数 N(或按 Enter 使用默认值):";
    std::string input;
    std::getline(std::cin, input); // 读取整行输入

    if (!input.empty()) {
        // 如果用户提供了输入,则尝试将其转换为整数
        std::stringstream ss(input);
        ss >> N;

        if (ss.fail() || N < 1 || N > 50) {
            std::cerr << "输入错误,使用默认值 N = 1\n";
            N = 1;
        }
    }

    // ...(其余代码)
}

通过这种修改,即使没有提供输入,C++ 代码也会运行并使用默认值 N=1

标签:python,c++,python-3.x,subprocess,python-3.8
From: 78796128

相关文章

  • 【Python自动化办公】用Pandas库自动化操作Excel表格,从读取、写入到数据处理和分析
    文末免费赠送精品编程资料~~前言Python的第三方Pandas库是数据处理和分析中的利器,其强大的功能可以帮助我们轻松地对Excel表格进行自动化操作。接下来,我们将介绍九个用Pandas库操作Excel的编程例子,并且每个例子都会涉及不同的知识点,确保全面掌握这个主题。1.读取和写入E......
  • 总结24个Python接单赚钱平台与详细教程,兼职月入5000+
    如果说当下什么编程语言最靠谱或者比较适合搞副业?答案肯定100%是:Python。python是所有语法中最简单易上手的语言,不需要特别的的英语词汇量,逻辑思维也不需要很差就能上手。而且学会了之后就能编写代码爬取各种数据,制作各种图表,提升工作效率。而且还能利用业余时间接点私活......
  • 当你第一次用C++string的assign会遇到这种情况
    当你第一次用string的assign时,会发现有一点小区别,见以下代码:stringstr1;str1.assign("helloC++");cout<<str1<<endl;stringstr2;str2.assign(str1,5);cout<<str1<<endl;stringstr3;str3.assign("helloC++",5);cout<<......
  • python安装第三方库的国内镜像
    直接:pipconfigsetglobal.index-urlhttps://pypi.doubanio.com/simple设置了全局的第三方库的下载文件镜像请求网址。安装第三方库:pipinstallscrapy--scrapy第三方库名称 pip从国内镜像安装的命令使用中国大陆地区的Python包镜像服务时,可以通过修改p......
  • 如何将Python嵌入.Net?
    我尝试基于文档此处和此处使用pythonnet将Python嵌入到.Net中。这是我的代码Runtime.PythonDLL=@"D:\Dev\Console\.conda\python311.dll";PythonEngine.Initialize();dynamicsys=Py.Import("sys");Console.WriteLine("Pythonversion:&quo......
  • 使用pybind11封装c++的dll,供python调用
    用pip安装好pybind11 文件清单,都写在一个目录里//文件名:add.cppextern"C"doubleadd(doublein1,doublein2){returnin1+in2;}//文件名:sub.cppextern"C"doublesub(doublein1,doublein2){returnin1-in2;}//文件名:mul.cppextern"......
  • python-myStudyList
     1  下载软件1.1下载python最新版本并安装下载地址:百度搜索python官网。WelcometoPython.org。 1.2官网学习网页:PythonTutorials–RealPython   1.3也可以下载集成环境软件Anaconda。 Anaconda软件商城官方正版免费下载(msc23.cn) 2 ......
  • P9304 「DTOI-5」3-1题解,c++树的遍历例题
    题意给定以n(1≤n≤1......
  • Python语法基础
    基本语句输入input() eg:输出print(内容)注释单行注释:#注释内容多行注释:"""注释内容"""数据类型: 字面量:整型、浮点数、字符串......intfloatstring查看数据类型:type(数据)查看数据类型 转换函数int(x):将x转换成整数类型float(x):将x转......
  • C/C++默认生成的几个函数s
    一、关键词类/结构体默认生成。拷贝/移动+构造/赋值=组合不同方式有4种,除默认、析构,共计6种。在使用时:拷贝/移动+赋值的,都是定义和赋值分开;拷贝/移动+构造的,都是定义和赋值一起。二:知识点默认构造函数Student():age(0){};拷贝构造函数Student(constStudent&i......