嵌套concurrent.futures.ThreadPoolExecutor

时间:2017-07-08 18:26:27

标签: python multithreading python-3.x python-multithreading concurrent.futures

我有一个程序,我目前正在使用concurrent.futures.ThreadPoolExecutor同时运行多个任务。这些任务通常受I / O限制,涉及对本地数据库和远程REST API的访问。但是,这些任务本身可以分成子任务,这也可以从并发中受益。

我希望在任务中使用concurrent.futures.ThreadPoolExecutor是安全的。我编写了一个玩具示例,这似乎有效:

import concurrent.futures


def inner(i, j):
    return i, j, i**j


def outer(i):
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        futures = {executor.submit(inner, i, j): j for j in range(5)}
        results = []
        for future in concurrent.futures.as_completed(futures):
            results.append(future.result())
    return results


def main():
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        futures = {executor.submit(outer, i): i for i in range(10)}
        results = []
        for future in concurrent.futures.as_completed(futures):
            results.extend(future.result())
    print(results)


if __name__ == "__main__":
    main()

尽管这个玩具示例似乎有效,但我还是有信心这是故意的。我希望它是,因为否则使用执行程序执行任意代码是不安全的,以防它也使用concurrent.futures来利用并发。

1 个答案:

答案 0 :(得分:0)

从其他线程生成线程绝对没有问题。您的情况也是如此。

尽管迟早会产生很多线程,但是产生更多的线程实际上会使您的软件变慢。

我强烈建议使用类似 asyncio 的库,该库可以漂亮地异步处理任务。它通过使用一个具有非阻塞io的线程来实现。结果可能会比普通线程甚至更快,因为开销要小得多。

如果您不想使用asyncio,为什么不在main内部创建另一个池执行程序,并将其传递给outer()函数呢?这样,您将拥有最多10个(2x5)的线程,而不是25(5x5)个线程?

您不能传递将main()调用到outer()的同一outer()执行程序,因为这可能会导致死锁(每个outer()等待另一个outer()进入在他们可以安排inner()之前完成。