简体   繁体   English

Python ThreadPoolExecutor 终止所有线程

[英]Python ThreadPoolExecutor terminate all threads

I am running a piece of python code in which multiple threads are run through threadpool executor.我正在运行一段 python 代码,其中多个线程通过线程池执行程序运行。 Each thread is supposed to perform a task (fetch a webpage for example).每个线程都应该执行一项任务(例如获取网页)。 What I want to be able to do is to terminate all threads, even if one of the threads fail.我想要做的是终止所有线程,即使其中一个线程失败。 For instance:例如:

with ThreadPoolExecutor(self._num_threads) as executor:
    jobs = []
    for path in paths:
        kw = {"path": path}
        jobs.append(executor.submit(start,**kw))
    for job in futures.as_completed(jobs):
        result = job.result()
        print(result)
def start(*args,**kwargs):
    #fetch the page
    if(success):
        return True
    else:
        #Signal all threads to stop

Is it possible to do so?有可能这样做吗? The results returned by threads are useless to me unless all of them are successful, so if even one of them fails, I would like to save some execution time of the rest of the threads and terminate them immediately.除非所有线程都成功,否则线程返回的结果对我来说毫无用处,因此即使其中一个失败,我想节省线程的 rest 的一些执行时间并立即终止它们。 The actual code obviously is doing relatively lengthy tasks with a couple of failure points.实际的代码显然是在做相对冗长的任务,有几个失败点。

If you are done with threads and want to look into processes, then this peace of code here looks very promising and simple, almost the same syntax as thread, but with the multiprocessing module.如果您已经完成了线程并想查看进程,那么这里的代码和平看起来非常有前途和简单,几乎与线程相同的语法,但使用多处理模块。

When the timeout flag expires the process is terminated, very convenient.当超时标志到期时进程终止,非常方便。

import multiprocessing

def get_page(*args, **kwargs):
    # your web page downloading code goes here

def start_get_page(timeout, *args, **kwargs):
    p = multiprocessing.Process(target=get_page, args=args, kwargs=kwargs)
    p.start()
    p.join(timeout)
    if p.is_alive():
        # stop the downloading 'thread'
        p.terminate()
        # and then do any post-error processing here

if __name__ == "__main__":
    start_get_page(timeout, *args, **kwargs)

You can try to use StoppableThread from func-timeout .您可以尝试使用func-timeout中的StoppableThread But terminating threads is strongly discouraged.强烈建议不要终止线程。 And if you need to kill a thread, you probably have a design problem.如果你需要杀死一个线程,你可能有一个设计问题。 Look at alternatives: asyncio coroutines and multiprocessing with legal cancel/terminating functionality.查看替代方案: asyncio协程和具有合法取消/终止功能的multiprocessing

I have created an answer for a similar question I had, which I think will work for this question.我已经为我遇到的类似问题创建了一个答案,我认为这将适用于这个问题。

from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep

NUM_REQUESTS = 100


def long_request(id):
    sleep(1)

    # Simulate bad response
    if id == 10:
        return {"data": {"valid": False}}
    else:
        return {"data": {"valid": True}}


def check_results(results):
    valid = True
    for result in results:
        valid = result["data"]["valid"]

    return valid


def main():
    futures = []
    responses = []
    num_requests = 0

    with ThreadPoolExecutor(max_workers=10) as executor:
        for request_index in range(NUM_REQUESTS):
            future = executor.submit(long_request, request_index)

            # Future list
            futures.append(future)

        for future in as_completed(futures):

            is_responses_valid = check_results(responses)

            # Cancel all future requests if one invalid
            if not is_responses_valid:
                executor.shutdown(wait=False)
            else:
                # Append valid responses
                num_requests += 1
                responses.append(future.result())

    return num_requests


if __name__ == "__main__":
    requests = main()
    print("Num Requests: ", requests)

This is how I would do it:我会这样做:

import concurrent.futures

def start(*args,**kwargs):
    #fetch the page
    if(success):
        return True
    else:
        return False

with concurrent.futures.ProcessPoolExecutor() as executor:
    results = [executor.submit(start, {"path": path}) for path in paths]
    concurrent.futures.wait(results, timeout=10, return_when=concurrent.futures.FIRST_COMPLETED)
    for f in concurrent.futures.as_completed(results):
        f_success = f.result()
        if not f_success:
            executor.shutdown(wait=False, cancel_futures=True) # shutdown if one fails
        else:
            #do stuff here

If any result is not True, everything will be shut down immediately.如果任何结果不为真,一切都将立即关闭。

In my code I used multiprocessing在我的代码中,我使用了多处理

import multiprocessing as mp
pool = mp.Pool()
for i in range(threadNumber):
    pool.apply_async(publishMessage, args=(map_metrics, connection_parameters...,))

pool.close()
pool.terminate()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM