使用超时

时间:2017-10-08 22:11:16

标签: python popen os.system

我是很长时间的SO读者,但这是我的第一个问题 我正在编写一个Python 3程序(我目前正在自学)来编译和运行一组C ++程序,这些程序应该做同样的事情(学生提交作业的提交)和将它们的输出与我在文本文件中已有的预期输出进行比较。

我正在寻找一种方法来运行这些允许我执行的可执行文件:

  • 如果没有结束,请在一定时限(例如10秒)后终止可执行文件。
  • 捕获可执行文件的所有输出(包括stdout,stderr和任何" shell"消息,如分段错误,内存/核心转储等等)
  • 即使可执行文件崩溃,或者已被强制终止(超过允许的时间),我仍然需要捕获" partial"输出到那一点。
  • 屏幕上没有任何内容(无输出或错误消息)。

到目前为止我尝试的所有内容(从类似问题的答案中)都缺少了一些东西。我无法找到满足我所有需求的(上述各点)。 以下是一些例子:

  • check_output()(如在this问题中)如果可执行文件崩溃,则不收集输出,并且某些消息(如核心转储)仍然会进入屏幕。

  • Popen()(如this中所示)似乎不会终止可执行文件(超出时间时)。 python线程结束(我希望我在这里使用正确的术语),但可执行文件继续运行。

  • 尽管不鼓励像 os.system()这样的方法,但无论如何我都尝试了它们,但它们并没有做得更好。

如果有人能指出我实现这一目标的方法,我会非常感激。我为任何语法错误道歉,因为英语不是我的第一语言。如果需要进一步的细节,请告诉我。 谢谢,

编辑:

这是我的python代码的最小副本:

from subprocess import STDOUT, check_output, TimeoutExpired

timeLimit = 3  # seconds
strOutput = ''

try:
    output = check_output('./a.out', stderr = STDOUT, timeout = timeLimit)
    strOutput = ''.join(map(chr, output))

except TimeoutExpired as e:
    strOutput += 'Error: Time limit exceeded, terminated..'

except Exception as e:
    strOutput += 'Error: ' + str(e)

f = open('report.txt','w')
f.write(strOutput)
f.close()

我还包括一些C ++示例,其中包含一些错误,用于创建用于测试先前代码的可执行文件。 它们都可以编译为: g ++ programName.cpp

#include <iostream>
using namespace std;

int main()
{
   cout << "This one is working correctly!" << endl;
}

以下代码导致&#34;除以零&#34;错误。 check_output()

未捕获此错误之前打印的语句
#include <iostream>
using namespace std;

int main()
{
   cout << "Trying to divide by zero.." << endl;
   cout << 3 / 0 << endl;
}

此代码等待意外输入(应在指定的超时后由脚本终止)

#include <iostream>
using namespace std;

int main()
{
   int x;
   cout << "Waiting for an unexpected input.." << endl;
   cin >> x;
}

我无法找到重现核心转储问题的可靠方法。核心转储是一个特例,因为 check_output()无法捕获其输出(它直接/仅直接进入屏幕)。

P.S。我无法添加标签&#39; check_output()&#39;,我没有足够的声誉。

2 个答案:

答案 0 :(得分:0)

一个简单的解决方案可能是使用到目前为止找到的所有解决方案,但不是一次运行程序,而是多次运行它们。

一次,确定运行时间, 另一次,确定输出 等等 这样,您还可以测试是否给出相同的输入它们提供相同的输出。 它可能不是您正在寻找的“超级优雅”解决方案,但它现在可能已经足够了,直到您在python中找到子进程的圣杯。

另外,您可以将输出重定向到文件以获得部分结果+超时,然后读取文件以获得部分结果。

答案 1 :(得分:0)

基于@CharlesDuffy注释,我简化了流程树以使其更平坦,并切换到subprocess.call(),这具有捕获&#34;部分&#34;输出(在可执行文件崩溃之前) 核心转储subprocess.call()仍未捕获,它会进入屏幕。
有没有办法捕获核心转储的输出?或至少阻止它在屏幕上显示?

from subprocess import call, TimeoutExpired

timeLimit = 3  # seconds
errMsg = ''
ret_code = 0
f = open('report.txt','w')

try:
    ret_code = call('./a.out', stdout = f, stderr = f, timeout = timeLimit)

except TimeoutExpired as e:
    errMsg = 'Error: Time limit exceeded, terminating..'

except Exception as e:
    errMsg = 'Error: ' + str(e)

if ret_code:
    errMsg = 'Error: ' + str(ret_code)

f.write(errMsg)
f.close()