2017-10-08 73 views
1

我很長一段時間的讀者,但這是我的第一個問題。
我正在編寫一個Python 3程序(我目前正在自學)編譯和運行一組C++程序,該程序應該做同樣的事情(學生爲作業提交)並將其輸出與我在文本文件中已經有了預期的輸出。從超時運行python的可執行文件

我正在尋找一種方式來運行這些可執行文件,允許我:

  • 在一定時限內終止後的可執行文件(比如,10秒),如果它沒有結束。
  • 捕獲可執行文件的所有輸出(包括stdout,stderr和任何「shell」消息,如分段錯誤,內存/內核轉儲等..)
  • 即使可執行文件崩潰或被強制終止超過允許的時間後),我需要捕獲到那個點的「部分」輸出。
  • 沒有任何內容出現在屏幕上(沒有輸出或錯誤消息)。

我到目前爲止試過的一切(從類似問題的答案中)都缺少了一些東西。我找不到滿足我所有需求的東西(上述要點)。 下面是一些例子:

  • 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++的樣品含有一些錯誤,以創建可執行文件使用測試以前的代碼。 它們都可以被編譯爲:克++ programName.cpp

#include <iostream> 
using namespace std; 

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

下面的代碼「被零除」錯誤導致。該錯誤之前打印的語句不是由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.我無法添加標籤'check_output()',我沒有足夠的聲望。

+1

你在使用什麼操作系統? – unutbu

+0

我目前正在我的Linux Mint 18.1筆記本電腦上運行,但此腳本旨在運行在學校的Ubuntu 16.04服務器上。 – Elman

+0

帶有'timeout'的'subprocess.call()'在異常處理程序中調用'p.kill()'和'p.wait()',如果超時過期,則調用該異常處理程序。因此,它實際上殺死了立即產生的進程。 –

回答

0

一個簡單的解決方案可以是使用迄今爲止找到的所有解決方案,但不是一次運行程序,而是多次運行它們。

一次,以確定運行時間, 另一個時間,以確定輸出 等 這樣,你也可以測試是否給他們提供相同的輸出相同的輸入。 它可能不是您正在尋找的「超級優雅」解決方案,但現在可能已經足夠,直到您在python中找到子進程的聖盃。

此外,您可以將輸出重定向到文件以獲得部分結果+超時,然後讀取部分結果的文件。

+0

謝謝你的回答。運行時間實際上不是問題。我只用它來避免無限循環的程序。我的主要問題是捕獲*全部*輸出。我無法找到一種方法將輸出重定向到使用check_output()的文件,所以我很感激你能否指出我的一個實際例子(我對Python比較新)。 – Elman

+0

這是我正在嘗試(重定向到一個文件)'output = check_output(['./a.out','> report.txt'],stderr = STDOUT,timeout = timeLimit)' – Elman

+0

也許只是運行一個運行其代碼的bash腳本。 –

0

基於@CharlesDuffy評論,我簡化了流程樹使其更加平滑,並切換到subprocess.call(),它具有捕獲「部分」輸出(在可執行文件崩潰之前)的優勢。
然而核心轉儲仍然沒有被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() 
相關問題