Python3 ThreadPoolExecutor 的用法

当我们处理 IO 密集型的任务的时候很容易相当多线程。

Python 因为 GIL 的关系我们没有办法在 CPU 密集型任务的情况下让解释器让出 CPU,但是当面对网络请求相关的任务的时候,我们却可以使用多线程切换来帮助我们节约 IO 等待时间。

Python3 之后我发现很多之前的恶心的写法现在都变得异常好用,比如要实现一个多线程的程序,现在也变得简单易懂。

只需要一个简单的上下文管理器 

with ThreadPoolExecutor(self.thread_concurrence) as executor:
    fs = [executor.submit(self._orm_iter_insert_bigquery, table_name, start, end) for start, end in start_end_list]
    for future in as_completed(fs):
        print(future.result())

就可以让我们的程序多线程运行。

 

executor.submit 可以 add 一个任务到多线程列表。

这里我们使用一个循环提交一些列任务到任务列表。注意 thread_concurrence 为我们指定的并发数,默认是 cpu_count * 5。

我使用一个 as_completed 来获取已经完成任务的结果。与它相对应的还有一个 wait 参数,wait 参数可以更精细的控制同步等待,具体的可以参看一下 reference 官方的文档。

 

值得注意的是,在写多线程程序的时候一定要注意自己在类上创建的很多连接是否是 线程安全

举个最简单的例子,大部分 Python 的 MySQL 连接都并非是线程安全的,如果多个线程使用同一个连接,你会发现你的多线程程序不起作用。

正确的方法是,如果你不确定你自己发起的客户端连接是否是线程安全或者可以复用的,最好是将 客户端的初始化,放在对应的多线程执行函数里面,这样就可以避免此类的问题。

类如这里就应该将相关连接放进函数 _orm_iter_insert_bigquery 中来避免线程不安全的情况。

 

最近开始使用 Python3.X 了,最大的感受就是之前很多觉得很难用的标准库经过这么多年的修改,已经变得好用了起来。例如我之前可能会为了达到多线程的效果去开很多进程或者使用 gevent 协程来帮助解决此类问题,但是现在

发现线程也很好用。使用方法也很简单 👍

 

 

Reference:

https://www.dongwm.com/post/use-concurrent-futures/  使用concurrent.futures的一些经验

https://docs.python.org/zh-cn/3/library/concurrent.futures.html  启动并行任务

https://slxiao.github.io/2019/06/10/mysql/  Python多线程程序中的MYSQL连接管理研究

posted @ 2020-08-10 18:55  piperck  阅读(5386)  评论(0编辑  收藏  举报