在异常上杀死循环python线程的最佳方法是什么?

时间:2014-09-23 15:55:55

标签: python multithreading python-2.7

我编写了一个程序,它使用线程在主程序循环时保持连接活动,直到它有异常或手动关闭。我的程序以1小时为间隔运行,连接超时为20分钟,因此我为我的架构中存在的每个连接元素生成一个线程。因此,如果我们有两个服务器连接到它,则连接到这两个服务器并保持连接并循环通过每个服务器检索数据。

我编写的程序工作正常,但是我似乎无法找到一种方法来处理它自己抛出异常的程序。这就是说,当主程序排除时,我找不到合适的处理线程的方法。如果程序除外,它只会挂起,因为线程也没有例外,它不能正确关闭,必须手动关闭。

有关如何在程序退出时处理清理线程的任何建议吗?

这是我的主题:

def keep_vc_alive(vcenter,credentials, api):
   vm_url =  str(vcenter._proxy.binding.url).split('/')[2]
   while True:
      try:
         logging.info('staying connected %s' % str(vm_url))
         vcenter.keep_session_alive()
      except:
         logging.info('unable to call current time of vcenter %s attempting to reconnect.' % str(vm_url))
         try:
            vcenter = None
            connected,api_version,uuid,vcenter = vcenter_open(60, api, * credentials)
         except:   
            logging.critical('unable to call current time of vcenter %s killing application, please have administrator restart the module.' % str(vm_url))
            break
      time.sleep(60*10)

然后我的异常清理代码如下,显然我知道.stop()不起作用,但老实说我不知道​​如何做我想做的事情。

except Abort:  # Exit without clearing the semaphore
   logging.exception('ApplicationError')
   try:
      config_values_vc = metering_config('VSphere',['vcenter-ip','username','password','api-version'])     
      for k in xrange(0, len(config_values_vc['username'])):   # Loop through each vcenter server
         vc_thread[config_values_vc['vcenter-ip'][k]].stop() 
   except:
      pass
   #disconnect vcenter
   try:
      for vcenter in list_of_vc_connections:
         list_of_vc_connections[vcenter].disconnect()
   except:
      pass
   try:        # Close the db is it is open (db is defined)
      db.close()
   except:
      pass
   sys.exit(1)

except SystemExit:
   raise

except:
   logging.exception('ApplicationError')
   semaphore('ComputeLoader', False)
   logging.critical('Unexpected error: %s' % sys.exc_info()[0])
   raise 

2 个答案:

答案 0 :(得分:2)

而不是睡觉,等待threading.Event()

def keep_vc_alive(vcenter,credentials, api, event):  # event is a threading.Event()
   vm_url =  str(vcenter._proxy.binding.url).split('/')[2]
   while not event.is_set():  # If the event got set, we exit the thread
      try:
         logging.info('staying connected %s' % str(vm_url))
         vcenter.keep_session_alive()
      except:
         logging.info('unable to call current time of vcenter %s attempting to reconnect.' % str(vm_url))
         try:
            vcenter = None
            connected,api_version,uuid,vcenter = vcenter_open(60, api, * credentials)
         except:   
            logging.critical('unable to call current time of vcenter %s killing application, please have administrator restart the module.' % str(vm_url))
            break
      event.wait(timeout=60*10)  # Wait until the timeout expires, or the event is set.

然后,在主线程中,在异常处理代码中设置事件:

except Abort:  # Exit without clearing the semaphore
   logging.exception('ApplicationError')
   event.set()  # keep_alive thread will wake up, see that the event is set, and exit

答案 1 :(得分:1)

在python中停止线程的普遍接受的方法是使用threading.Event对象。

后面的算法通常如下所示:

import threading
...
threads = []
#in the main program
stop_event = threading.Event()
#create thread and store thread and stop_event together
thread = threading.Thread(target=keep_vc_alive, args=(stop_event))
threads.append((thread, stop_event))
#execute thread
thread.start()
...
#in thread (i.e. keep_vc_alive)
# check is_set in stop_event
while not stop_event.is_set():
    #receive data from server, etc
    ...
...
#in exception handler
except Abort:
    #set the stop_events
    for thread, stop_event in threads:
        stop_event.set()
    #wait for threads to stop
    while 1:
        #check for any alive threads
        all_finished = True
        for thread in threads:
            if thread.is_alive():
                all_finished = False
        #keep cpu down
        time.sleep(1)