Python中的线程、进程池
0X00 线程池和进程池
多线程和多进程在平时编程中是挺常见的操作,不过控制进程和线程的数量是一件比较麻烦的事情。尤其是线程,之前在搜索到的关于线程池的内容多数都是“造轮子”,实际上Python已经给我们造好了这个轮子。文档在这里,甚至还是中文的https://docs.python.org/zh-cn/3.7/library/concurrent.futures.html#module-concurrent.futures
我这里简单的整理了一下,做个小样例展示出来方便查阅。这里就假装大家对Python有一定的了解,而且也对操作系统中的线程和进程有一些了解了。(哦对了,还需要了解一下GIL才行)
0X01 使用线程池
1#!/usr/bin/env python
2
3import time
4from concurrent.futures import ThreadPoolExecutor
5
6
7# 定义一个用来测试的方法
8def test_func(num):
9 time.sleep(1)
10 res = num * num
11 print(res)
12 return res
13
14
15if __name__ == '__main__':
16 # 构造一个可以容纳两个线程的线程池
17 thread_pool = ThreadPoolExecutor(max_workers=2)
18
19 with thread_pool as pool:
20 for i in range(5):
21 pool.submit(test_func, i) # 将任务提交到线程池里这段代码执行下来耗时3s大概,因为有两个线程在执行,所以第一次执行了两个任务,第二次两个,第三次一个。可以通过调整range()数量和max_workers来观察输出结果。
0X02 使用进程池
1#!/usr/bin/env python
2
3import time
4from concurrent.futures import ProcessPoolExecutor
5
6
7def test_func(num):
8 time.sleep(1)
9 res = num * num
10 print(res)
11 return res
12
13
14if __name__ == '__main__':
15 process_pool = ProcessPoolExecutor(max_workers=2)
16 with process_pool as pool:
17 for i in range(5):
18 pool.submit(test_func, i)可以看到跟上面线程池的方案比起来就只是把ThreadPoolExecutor换成了ProcessPoolExecutor而已。
0X03 通用的部分
其中ProcessPoolExecutor和ThreadPoolExector均接收参数max_workers,不过由于线程和进程的本质区别,所以还是要适当设置这两个值。默认情况下max_workers的值设置为自己的逻辑处理器个数,如果你的CPU是4核8线程的那就自动设置成8。在 Windows 上,max_workers 必须小于等于 61,否则将引发 ValueError。
pool.submit()中的参数是submit(func, *args),所以把需要传递给func的参数逐个写在后面就好了。
pool.submit()后会返回一个Future对象,这个对象可以查看任务的执行情况:cancel()可以取消任务(如果任务还没开始的话);cancelled()查看任务是否被取消了;running()任务是否在进行;done()任务是否执行完了。使用result()可以获得任务的结果,还未完成的任务会等待结果,可以使用timeout参数指定等待多少秒。
与Python无关的部分
- 使用多线程要注意不要开过多的线程,因为在线程中切换也需要资源,线程过多可能反而会影响效率;
- 进程不宜过多,防止系统负载过大;
- 使用多进程时要万分小心不要失控,因为进程数量一旦失控可能会导致系统宕机(相关内容可以搜索了解一下
fork炸弹)。
如果这篇文章对你有帮助,可以请我喝杯咖啡 ☕
评论