2016-06-10 65 views
2

我有一個python腳本,運行時間很長。有時我需要中止並稍後運行它。它將當前結果轉儲到一個pickle文件中,但在錯誤的時間中止(CTLR + C)文件被損壞。特殊功能完成運行後中止python腳本

有沒有辦法讓腳本完成該任務並在事後中止? 我不知道在哪裏尋找。

謝謝

編輯:我的程序看起來有點像這樣:

import pickle 


for key in keylist: 
    do_smth(mydict) 
    with open('myfile.p','w+b') as f: 
     pickle.dump(mydict,f) 

EDIT2:謝謝你們,請嘗試:除了... ...就像一個魅力。 因爲我是腳本的唯一用戶,所以我不需要「保存」版本。但是我肯定會研究它(現在我不熟悉線程)。

我也改變了我的循環,我只會醃我的文件,如果發生異常或循環完成後。

import pickle 

for key in keylist: 
    try: 
     do_smth(mydict) 
    except KeyboardInterrupt: 
     print("Saving data ...") 
     with open('myfile.p','w+b') as f: 
      pickle.dump(mydict,f) 

    with open('myfile.p','w+b') as f: 
     pickle.dump(mydict,f) 

回答

2

按Ctrl +ç實際上拋出所謂KeyboardInterrupt異常的一種特殊類型。所以,如果您放棄腳本以稍後運行該腳本的方式發送該異常,則可以在退出之前保存數據。這可以通過將代碼包裝在try-except塊中並捕獲KeyboardInterrupt異常來完成。
一個例子是這樣的:

try: 
    # your main code here 
except KeyboardInterrupt: 
    # do the saving here 
    exit(-1) # exit the program with the return code -1 

關於註釋:確保你馬上把這例外。
這是因爲如果您發送它,代碼將轉到保存部分,該部分沒有捕獲異常的塊。所以如果你多次發送它,你的數據可能會被不正確地保存。

+0

然而,儲蓄可以通過CTRL + C中斷,再次 – DomTomCat

+0

@DomTomCat不,不能。該例外情況是由有興趣保存其數據的用戶生成的。所以我懷疑他會多次發送它。當然,這是一種可能性,但只是建議用戶會更簡單。更簡單,更好的 – Leva7

+2

以及其他人使用該代碼時最新的版本!但是,他們可能會小心,對。但是數據也可能會腐敗 - 例如它只是在調用CTRL + C時被更新 – DomTomCat

2

要保護兩個操作:

  1. 寫入數據的,一旦CTRL + C一直打到您的數據的更新(不一定是計算)

如果僅使用try,except塊,則可能會簡單地中斷這兩者,並使數據或輸出文件處於損壞狀態。

This answer有一個有趣的評論:

Python的線程不能只是一個特殊的C API被中斷。

所以,你可能想要做的就是趕在你的代碼KeyboardInterruptexcept分支內,開始其寫出當前數據的線程。我做了一個例子:

import time 
from threading import Thread 

def heavy(n): 
    for i in range(10000): 
     time.sleep(1) 
     print("doing some computation") 

def noInterrupt(path, obj): 
    try: 
     print("interrupted, writing out data (try to press CTRL+C again)...") 
     for i in range(5): 
      time.sleep(1) 
      print("...wrote block %d/5" % i) 
    finally: 
     print("DONE writing file") 


mydata = [] 
try: 
    # press CTRL+C somewhere here 
    # manipulate data 
    for i in range(1000): 
     heavy(i) 
except KeyboardInterrupt: 
    a = Thread(target=noInterrupt, args=("path/to/file", mydata)) 
    a.start() 
    a.join() 

注:請不要忘記,你的數據的操作可以會損壞與KeyboardInterrupt也一樣,所以你可能想確保你保護更新數據的過程( ?與其他線程)

+0

順便說一句,'print(heavy(i))'會輸出''做一些計算''和''None'',因爲你打印的返回值是功能'沉重' – Leva7

+0

哦謝謝,這裏有一些遺留代碼:-)更正 – DomTomCat

0

也可以爲KeyboardInterrupt創建一個處理程序:

import signal 
import sys 
def signal_handler(signal, frame): 
     #make sure you save the file 
     sys.exit(0) 
signal.signal(signal.SIGINT, signal_handler)