2016-07-23 19 views
0

Kann die zugrundeliegende Ausführung eines Threads abgebrochen werden, nachdem es wegen Timeout abgebrochen wurde?Python 3: Thread: Töten aufrufbare Ausführung nach Abbruch wegen Timeout?

Ich verfolge den folgenden Threading-Ansatz hier zu finden: Timeout a Python Callable

Eine überarbeitete Version dieses Codes für Python 3 ist unten.

Dieser Code ist Timeout richtig eine aufrufbare Funktion durch ein RuntimeError werfen, wenn implementiert threading.Thread.abort() genannt wird, die, wie erwartet, wenn es Timeout-Wert zu threading.Thread.join(timeout) zugewiesen wurde.

Obwohl der Thread abgebrochen wurde, wird die zugrunde liegende Callable dennoch ausgeführt.

Frage: Wie kann ich diesen Thread beenden, nachdem er abgebrochen wurde, um zu verhindern, dass die zugrunde liegende Callable weiter ausgeführt wird, ohne die übergeordnete ausführbare Datei zu löschen?

Hier ist mein Code:

import datetime as dt 
import threading 

def run_command_with_threaded_timeout(
    func, 
    fargs=None, 
    fkwargs=None, 
    threaded_run_timeout_secs=None 
): 
    class TimedThread(threading.Thread): 
     """An abortable thread, by raising an exception inside its 
     context. 
     """ 

     def __init__(self): 
      super(TimedThread, self).__init__() 
      self.exc_info = (None, None, None) 

     def run(self): 
      self.started_at = dt.datetime.now() 
      try: 
       args = fargs if fargs else list() 
       kwargs = fkwargs if fkwargs else dict() 
       request_func = partial(func, *args, **kwargs) 
       self.result = request_func() 
      except: 
       # save the exception as an object attribute 
       self.exc_info = sys.exc_info() 
       self.result = None 

      self.ended_at = dt.datetime.now() 

     def abort(self): 
      self.ended_at = dt.datetime.now() 
      threaded_run_diff = self.ended_at - self.started_at 
      threaded_run_diff_secs = threaded_run_diff.seconds     
      if threaded_run_diff_secs >= threaded_run_timeout_secs: 
       raise RuntimeError(
        "Threaded Run: Timed Out" 
        ) 

      raise RuntimeError(
       "Threaded Run: Aborted" 
      ) 

    t = TimedThread() 
    t.start() 
    t.join(timeout=threaded_run_timeout_secs) 
    if t.exc_info[0] is not None: # if there were any exceptions 
     exc_type, exc_value, exc_traceback = t.exc_info 
     # Raise the exception/traceback inside the caller 
     raise exc_type.with_traceback(exc_value, exc_traceback) 

    if t.is_alive(): 
     t.abort() 
     diff = t.ended_at - t.started_at    
     raise RuntimeError("%(f)s timed out after %(d)r seconds" % 
          {'f': func, 'd': diff.seconds}) 

    return t.result 

Antwort

0

Was ich gelesen habe, ist, dass ein Thread kann nicht von außen getötet werden.

Was kann getan werden, ist eine globale, die nach Thread zu bestimmen, ob es noch am Leben ist.

global is_alive = True 
kwargs = { 
    'config_job': config_job, 
    'config_request_params': config_request_params, 
    'config_request_credentials': config_request_credentials, 
    'config_request_retry': config_request_retry 
} 

try: 
    response = run_command_with_threaded_timeout(
     func=cmd, 
     fargs=None, 
     fkwargs=kwargs, 
     timeout_sec=timeout_sec 
    ) 
except Exception as ex: 
    is_alive = False 
    raise