2016-12-01 56 views
0

在Python中給定的時間量之後終止函數(仍在運行)的最佳方法是什麼?這是到目前爲止,我已經找到了兩種方法:在給定的時間量後終止python函數

這樣說,是我們的基本功能:

import time 
def foo(): 
    a_long_time = 10000000 
    time.sleep(a_long_time) 

TIMEOUT = 5 # seconds 

1.多重方法

import multiprocessing 

if __name__ == '__main__': 
    p = multiprocessing.Process(target=foo, name="Foo") 
    p.start() 

    p.join(TIMEOUT) 

    if p.is_alive() 
     print('function terminated') 
     p.terminate() 
     p.join() 

2.信號途徑

import signal 

class TimeoutException(Exception): 
    pass 

def timeout_handler(signum, frame): 
    raise TimeoutException 

signal.signal(signal.SIGALRM, timeout_handler) 


signal.alarm(TIMEOUT)  
try: 
    foo() 
except TimeoutException: 
    print('function terminated') 

這兩種方法在範圍,安全性和可用性方面有哪些優缺點?有沒有更好的方法?

回答

1

那麼,一如既往,這取決於。

正如您可能已經驗證的那樣,這兩種方法都有效。我想說這取決於你的應用程序和正確的實現(你的信號傳輸方法有點不對......)

如果實施正確,兩種方法都可以被認爲是「安全」的。這取決於你的foo函數之外的主程序是否需要做某件事,或者它是否可以坐下來等待foo完成或超時。信令方法不允許任何並行處理,因爲您的主程序將在foo()中,直到它完成或超時。但是你需要然後化解信號。如果你的foo在一秒鐘內完成,你的主程序將離開try/except結構,並在四秒鐘之後... kaboom ...引發異常並可能未被捕獲。不好。

try: 
    foo() 
    signal.alarm(0) 
except TimeoutException: 
    print ("function terminated") 

解決了這個問題。

我個人更喜歡多處理方法。它更簡單,並且不需要信號和異常處理,如果您的程序執行不是您希望信號發生時期望的那樣,理論上可能會出錯。如果你的程序在join()中等待,那麼你就完成了。但是,如果您希望在等待時在主流程中執行某些操作,則可以輸入一個循環,跟蹤變量中的時間,檢查是否超時,如果是,則終止流程。如果進程仍在運行,您只需使用連接,只需很小的超時時間即可「偷看」。

另一種方法,取決於你的foo(),是使用具有類或全局變量的線程。如果您FOO保持,而不是處理指令的可能等待很長的時間來完成一個命令,你可以添加一個if從句有:

def foo(): 
    global please_exit_now 
    while True: 
     do_stuff 
     do_more_stuff 
     if foo_is_ready: 
      break 
     if please_exit_now is True: 
      please_exit_now = False 
      return 
    finalise_foo 
    return 

如果do_stuff和do_more_stuff完全在合理的時間量,然後你可以在你的主程序中處理東西,並將全局please_exit_now設置爲True,並且你的線程最終會注意到並退出。

雖然我可能只是爲你的多處理和加入。

Hannu

+0

感謝您接觸到信號的方法。我想我正在計劃使用多處理機制,因爲它具有並行性和簡單性。 – Anna

+1

在多處理中,記住用try/except封裝你的p.terminate()。如果您的應用程序被大量使用,它最終會遇到罕見的情況,其中p.join()超時,因爲p仍在運行,p.is_alive()返回true,p在此之後立即完成,並且當您調用p.terminate()隨着p不再運行,將會引發異常。你可以很容易地忽略這個異常,因爲你的應用程序的狀態是你想要的(沒有運行),但是如果沒有被捕獲,你的主程序會在這個時候退出。 – Hannu

+0

實際上,你不需要is_alive()檢查,因爲它不會提供任何額外的有用信息,因爲p可能會在is_alive和下一個命令之間死掉。只需在try/except內部調用p.terminate()並忽略異常。它要麼成功要麼失敗,你的p將會消失。 – Hannu