2017-09-14 158 views
6

我正在使用線程從API url檢查標頭狀態碼。如果條件成立,我怎樣才能斷開循環/停止所有其他線程?請檢查下面的代碼..在真實條件下Python退出所有正在運行的線程

import logging, time, threading, requests 

#: Log items 
logging.basicConfig(format='%(asctime)s %(levelname)s : %(message)s', level=logging.INFO) 

class EppThread(threading.Thread): 
    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None): 
     threading.Thread.__init__(self, group=group, target=target, name=name, verbose=verbose) 
     self.args = args 

    def run(self): 
     startTime = time.time() 
     url = self.args[0] 
     limit = self.args[1] 

     for i in range(limit): 
      response = requests.get(url) 
      if response.status_code != 200: 
       break 
       #Exit other similar threads (with same url) 
      else: 
       print('Thread {0} - success'.format(thread.getName())) 

     print('process completed') 
     # Send Email 


number_of_threads = 5 
number_of_requests = 100 

urls = ['https://v1.api.com/example', 'https://v2.api.com/example'] 

if __name__ == '__main__': 
    startTime = time.time() 

    for url in urls: 
     threads = [] 
     for i in range(number_of_threads): 
      et = EppThread(name = "{0}-Thread-{1}".format(name, i + 1), args=(url, number_of_requests)) 
      threads.append(et) 
      et.start() 

    # Check if execution time is not greater than 1 minute 
    while len(threads) > 0 and (time.time() - startTime) < 60: 
     time.sleep(0.5) 
     for thread in threads: 
      if not thread.isAlive(): 
       threads.remove(thread) 
       print('Thread {0} terminated'.format(thread.getName())) 

    os._exit(1) 

請建議,如果條件在任何正在運行的線程得到真的停止執行代碼一些更好的方法。

感謝您的幫助。

+1

只是爲了澄清,要退出所有線程,包括主,任何時候任何線程有不正確的連接('響應。 status_code!= 200')。這是否準確? –

+0

@EricEdLohmar是的,這是正確的。 – seoppc

回答

6

,這裏要注意的重要一點是,當Threadrun方法完成,Thread設置爲死者和垃圾收集。所以我們真正需要的是打破該循環的布爾類變量。對於從該類和子類實例化的所有對象,類變量都是相同的;所以一旦我們設置它,都在我們的類的對象將採取同樣的方式:

import logging, time, threading, requests 

#: Log items 
logging.basicConfig(format='%(asctime)s %(levelname)s : %(message)s', level=logging.INFO) 


class EppThread(threading.Thread): 
    kill = False # new Boolean class variable 
    url = 'https://v1.api.com/example' # keep this in mind for later 

    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None): 
     threading.Thread.__init__(self, group=group, target=target, name=name, verbose=verbose) 
     self.args = args 

    def run(self): 
     limit = self.args[0] 

     for i in range(limit): 
      response = requests.get(self.url) 
      if response.status_code != 200: 
       self.kill = True # ends this loop on all Threads since it's changing a class variable 

      else: 
       print('Thread {0} - success'.format(self.getName())) # changed to self.getName() 

      if self.kill: # if kill is True, break the loop, send the email, and finish the Thread 
       break 

     print('process completed') 
     # Send Email 


number_of_threads = 5 
number_of_requests = 100 

if __name__ == '__main__': 
    startTime = time.time() 

    threads = [] 
    for i in range(number_of_threads): 
     et = EppThread(name="{0}-Thread-{1}".format(name, i + 1), args=(number_of_requests)) 
     threads.append(et) 
     et.start() 

    # Check if execution time is not greater than 1 minute 
    while threads and time.time() - startTime < 60: # removed len() due to implicit Falsiness of empty containers in Python 
     time.sleep(0.5) 
     for thread in threads: 
      if not thread.isAlive(): 
       threads.remove(thread) 
       print('Thread {0} terminated'.format(thread.getName())) 

    EppThread.kill = True 

現在,當任何EppThreads的有一個不好的方面,它設置類變量True,這使得所有其他的EppThread也打破了循環。我還在最後添加了EppThread.kill = True,所以如果超過1分鐘的運行時間,它會更乾淨地打破請求循環。

最後,我添加了url類變量。這是因爲你表示有興趣同時運行不同的URL,只殺掉那些具有不良聯繫的URL。在這一點上你所要做的全部是子類EppThread並覆蓋killurl

class EppThread2(EppThread): 
    kill = False 
    url = 'https://v2.example.com/api?$awesome=True' 

然後你可以實例EppThread2,並把它添加到列表threads,一切都應該工作,只要你想它。

+0

但條件滿足時如何告訴主程序退出? – seoppc

+0

你可以使用'exit()'內建函數。 '如果條件:exit()' –

+0

Nvm。我現在知道了。根據我目前對您的問題的理解,我將創建另一個答案。 –

5

您可以創建一個共享相同網址的所有線程共享的event object。當您遇到線程中的錯誤時,請設置事件。然後,在您的運行循環中檢查事件。如果它發生,通過打破循環殺死線程。

下面是您的示例修改爲使用Event的版本。

import logging, time, threading, requests 

#: Log items 
logging.basicConfig(format='%(asctime)s %(levelname)s : %(message)s', level=logging.INFO) 

class EppThread(threading.Thread): 
    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None, bad_status=None): 
     threading.Thread.__init__(self, group=group, target=target, name=name, verbose=verbose) 
     self.args = args 
     self.bad_status = bad_status 

    def run(self): 
     startTime = time.time() 
     url = self.args[0] 
     limit = self.args[1] 

     for i in range(limit): 
      if self.bad_status.is_set(): 
       # break the loop on errors in any thread. 
       break 
      response = requests.get(url) 
      if response.status_code != 200: 
       # Set the event when an error occurs 
       self.bad_status.set() 
       break 
       #Exit other similar threads (with same url) 
      else: 
       print('Thread {0} - success'.format(thread.getName())) 

     print('process completed') 
     # Send Email 


number_of_threads = 5 
number_of_requests = 100 

urls = ['https://v1.api.com/example', 'https://v2.api.com/example'] 

if __name__ == '__main__': 
    startTime = time.time() 

    threads = [] 
    for url in urls: 
     # Create an event for each URL 
     bad_status = threading.Event() 
     for i in range(number_of_threads): 
      et = EppThread(name = "{0}-Thread-{1}".format(name, i + 1), args=(url, number_of_requests), bad_status=bad_status) 
      threads.append(et) 
      et.start() 

    # Check if execution time is not greater than 1 minute 
    while len(threads) > 0 and (time.time() - startTime) < 60: 
     time.sleep(0.5) 
     for thread in threads: 
      if not thread.isAlive(): 
       threads.remove(thread) 
       print('Thread {0} terminated'.format(thread.getName())) 

os._exit(1) 

threading.Event類適用於線程和進程。所以,如果在某個時候你想切換到使用Process,它會「正常工作」。

+0

此方法是否單獨處理網址?例如,如果url1失敗,只有使用url1的線程停止。對? – seoppc

+0

它的確如此。您正在爲網址中的每個網址創建一個事件,然後將該事件分配給該網址的所有線程。 –

+0

您不能在列表中的循環中使用'threads.remove'。另外,你爲每個'url'重新創建'threads'。 –

1

進口sys

下面是一個例子:

import sys 

list = [] 
if len(list) < 1: 
    sys.exit("You don\'t have any items in your list") 
相關問題