Python在truthy条件下退出所有正在运行的线程

时间:2017-09-14 18:58:33

标签: python multithreading

我正在使用线程来检查API网址中的标头状态代码。如果条件为真,我如何打破/停止所有其他线程。请检查以下代码..

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)

如果在任何正在运行的线程中条件成立,请建议一些更好的方法来阻止代码执行。

感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

这里要注意的一件重要事情是,当run的{​​{1}}方法完成后,Thread将设置为dead并收集垃圾。所以我们真正需要的是一个布尔类变量来打破这个循环。对于从该类和子类实例化的所有对象,类变量是相同的;所以一旦我们设置它,我们类中的所有对象都将以相同的方式运行:

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,以便在超过1分钟的运行时间时更加干净地打破请求循环。

最后,我添加了EppThread.kill = True类变量。这是因为您表示有兴趣同时运行不同的URL并且只杀死那些特别连接不良的URL。此时您所要做的只是子类url并覆盖EppThreadkill

url

然后,您可以实例化class EppThread2(EppThread): kill = False url = 'https://v2.example.com/api?$awesome=True' 并将其添加到EppThread2列表中,一切都应该按照您的意愿运行。

答案 1 :(得分:5)

您可以创建在共享相同网址的所有线程之间共享的event object。当您在线程中遇到错误时,请设置该事件。然后,在运行循环中检查事件。如果它已经发生,请通过打破循环来杀死线程。

以下是修改后使用事件的示例版本。

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,它就会“正常工作”。

答案 2 :(得分:1)

导入sys

以下是一个例子:

import sys

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