【一】什么是池
-
池是用来保证计算机硬件安全的情况下最大限度的利用计算机
-
池降低了程序的运行效率,但是保证了计算机硬件的安全,从而保证程序的正常运行
【二】线程池
【1】语法
from concurrent.futures import ThreadPoolExecutor # 默认开设当前计算机 cpu 个数五倍数的线程数 # 可以指定线程总数 pool = ThreadPoolExecutor(5)
【2】原理
-
池子造出来后 里面固定存在五个线程
-
这五个线程不会存在出现重复创建和销毁的过程
【3】优点
-
避免了重复创建五个线程的资源开销
【4】使用方法
(0)任务的提交方式
-
同步:提交任务之后原地等待任务的返回结果,期间不做任何事
-
异步:提交任务之后不等待任务的返回结果,继续执行代码
(1)同步提交
from concurrent.futures import ThreadPoolExecutor import time # 构造线程池,指定线程总数 pool = ThreadPoolExecutor(5) # 定义线程任务 def task(n): print(n) time.sleep(2) # 向线程池中添加线程任务 def normal(): pool.submit(task,1) # 异步提交 - 先执行子线程再打印主线程 print('\nthis is a main task') # 1 # this is a main task if __name__ == '__main__': normal()
(2)异步提交
from concurrent.futures import ThreadPoolExecutor import time # 构造线程池,指定线程总数 pool = ThreadPoolExecutor(5) # 定义线程任务 def task(n): print(n) time.sleep(2) # 向线程池中添加线程任务 def normal(): pool.submit(task, 1) # 异步提交 - 先执行子线程再打印主线程 print('this is a main task') # 1 # this is a main task def many_steps(): for i in range(20): pool.submit(task, i) print('this is a main task') if __name__ == '__main__': many_steps() # 0 # 1 # 2 # 3 # 4 # this is a main task # 先执行五个子线程,再回到主线程 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # 19
【5】异步返回值
(1)查看异步回调对象
from concurrent.futures import ThreadPoolExecutor import time # 构造线程池,指定线程总数 pool = ThreadPoolExecutor(5) # 定义线程任务 def task(n): print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 def many_steps(): for i in range(5): # 提交任务到线程池,并获取到返回值 res = pool.submit(task, i) print(f'这是 pool的返回值:>>>>{res}') # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果 # <Future at 0x134d3fcd0 state=pending> print(f'这是 pool的返回值:>>>>{res.result()}') # None # 程序由并发变成了串行 # 返回的结果是 None ---> 任务的返回结果 ----> 拿到了异步提交的返回结果 # res.result() : 拿到的就是异步提交的任务的返回结果 print('this is a main task') # 这是线程任务中的 n :>>>> 0这是 pool的返回值:>>>><Future at 0x104f36350 state=running> # # 这是 pool的返回值:>>>>0 # 这是 pool的返回值:>>>><Future at 0x11747b460 state=pending> # 这是线程任务中的 n :>>>> 1 # 这是 pool的返回值:>>>>2 # 这是 pool的返回值:>>>><Future at 0x104f36350 state=pending> # 这是线程任务中的 n :>>>> 2 # 这是 pool的返回值:>>>>4 # 这是 pool的返回值:>>>><Future at 0x11747b160 state=pending> # 这是线程任务中的 n :>>>> 3 # 这是 pool的返回值:>>>>6 # 这是 pool的返回值:>>>><Future at 0x104f36350 state=pending> # 这是线程任务中的 n :>>>> 4 # 这是 pool的返回值:>>>>8 # this is a main task if __name__ == '__main__': many_steps()
(2)调用异步回调对象
from concurrent.futures import ThreadPoolExecutor import time # 构造线程池,指定线程总数 pool = ThreadPoolExecutor(5) # 定义线程任务 def task(n): print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 def many_steps(): task_list = [] for i in range(5): # 提交任务到线程池,并获取到返回值 res = pool.submit(task, i) print(f'这是 pool的返回值:>>>>{res}') # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果 # <Future at 0x134d3fcd0 state=pending> task_list.append(res) for task_every in task_list: print(f'这是 pool的返回值:>>>>{task_every.result()}') # None # 程序由变成了串行 # res.result() : 拿到的就是异步提交的任务的返回结果 # 程序运行的结果是有序的 print('this is a main task') # 这是线程任务中的 n :>>>> 0这是 pool的返回值:>>>><Future at 0x154e6bfa0 state=running> # # 这是线程任务中的 n :>>>> 1 # 这是 pool的返回值:>>>><Future at 0x15511bc10 state=running> # 这是线程任务中的 n :>>>> 2这是 pool的返回值:>>>><Future at 0x15511beb0 state=running> # # 这是线程任务中的 n :>>>> 3 # 这是 pool的返回值:>>>><Future at 0x1551401c0 state=running> # 这是线程任务中的 n :>>>> 4 # 这是 pool的返回值:>>>><Future at 0x1551404c0 state=running> # 这是 pool的返回值:>>>>0 # 这是 pool的返回值:>>>>2 # 这是 pool的返回值:>>>>4 # 这是 pool的返回值:>>>>6 # 这是 pool的返回值:>>>>8 # this is a main task if __name__ == '__main__': many_steps()
【6】pool.shutdown()
-
等待所有子线程结束后再打印程序运行结果
from concurrent.futures import ThreadPoolExecutor import time # 构造线程池,指定线程总数 pool = ThreadPoolExecutor(5) # 定义线程任务 def task(n): print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 def many_steps(): task_list = [] for i in range(5): # 提交任务到线程池,并获取到返回值 res = pool.submit(task, i) print(f'这是 pool的返回值:>>>>{res}') # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果 # <Future at 0x134d3fcd0 state=pending> task_list.append(res) # 关闭线程池 - 等待所有的线程池中的任务运行完毕 pool.shutdown() for task_every in task_list: print(f'这是 pool的返回值:>>>>{task_every.result()}') # None # 程序由变成了串行 # res.result() : 拿到的就是异步提交的任务的返回结果 # 程序运行的结果是有序的 print('this is a main task') # 这是线程任务中的 n :>>>> 0 # 这是 pool的返回值:>>>><Future at 0x13a713fa0 state=running> # 这是线程任务中的 n :>>>> 1 # 这是 pool的返回值:>>>><Future at 0x13a9c3c70 state=running> # 这是线程任务中的 n :>>>> 2 # 这是 pool的返回值:>>>><Future at 0x13a9c3f10 state=running> # 这是线程任务中的 n :>>>> 3 # 这是 pool的返回值:>>>><Future at 0x13a9ec220 state=running> # 这是线程任务中的 n :>>>> 4 # 这是 pool的返回值:>>>><Future at 0x13a9ec520 state=running> # 这是 pool的返回值:>>>>0 # 这是 pool的返回值:>>>>2 # 这是 pool的返回值:>>>>4 # 这是 pool的返回值:>>>>6 # 这是 pool的返回值:>>>>8 # this is a main task if __name__ == '__main__': many_steps()
【三】进程池的使用
-
开设进程的进程 ID 号不会发生改变
import os from concurrent.futures import ProcessPoolExecutor import time # 构造进程池,指定进程总数 pool = ProcessPoolExecutor(5) # 定义线程任务 def task(n): print(n, f'当前进程的进程号:>>>{os.getpid()}') print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 def many_steps(): task_list = [] for i in range(5): # 提交任务到进程池,并获取到返回值 res = pool.submit(task, i) print(f'这是 pool的返回值:>>>>{res}') # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果 # <Future at 0x134d3fcd0 state=pending> task_list.append(res) # 关闭进程池 - 等待所有的进程池中的任务运行完毕 pool.shutdown() for task_every in task_list: print(f'这是 pool的返回值:>>>>{task_every.result()}') # None # 程序由变成了串行 # res.result() : 拿到的就是异步提交的任务的返回结果 # 程序运行的结果是有序的 print('this is a main task') # 这是 pool的返回值:>>>><Future at 0x136434a30 state=running> # 这是 pool的返回值:>>>><Future at 0x136435630 state=running> # 这是 pool的返回值:>>>><Future at 0x136435810 state=pending> # 这是 pool的返回值:>>>><Future at 0x136435bd0 state=pending> # 这是 pool的返回值:>>>><Future at 0x136435ba0 state=pending> # 0 当前进程的进程号:>>>44758 # 这是线程任务中的 n :>>>> 0 # 1 当前进程的进程号:>>>44759 # 这是线程任务中的 n :>>>> 1 # 2 当前进程的进程号:>>>44756 # 这是线程任务中的 n :>>>> 2 # 3 当前进程的进程号:>>>44757 # 这是线程任务中的 n :>>>> 3 # 4 当前进程的进程号:>>>44760 # 这是线程任务中的 n :>>>> 4 # 这是 pool的返回值:>>>>0 # 这是 pool的返回值:>>>>2 # 这是 pool的返回值:>>>>4 # 这是 pool的返回值:>>>>6 # 这是 pool的返回值:>>>>8 # this is a main task if __name__ == '__main__': many_steps()
【四】异步回调函数
-
add_done_callback(call_back)
-
add_done_callback(call_back) 返回值正是我们的上面 pool的返回的结果
import os from concurrent.futures import ProcessPoolExecutor import time # 构造进程池,指定进程总数 pool = ProcessPoolExecutor(5) # 定义线程任务 def task(n): print(n, f'当前进程的进程号:>>>{os.getpid()}') print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 # 定义一个异步回调函数 def call_back(n): print(f'call_back>>>:{n}') def many_steps(): task_list = [] for i in range(5): # 提交任务到进程池,并获取到返回值,添加一个异步回调函数 res = pool.submit(task, i).add_done_callback(call_back) print(f'这是 pool的返回值:>>>>{res}') print('this is a main task') # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # this is a main task # 0 当前进程的进程号:>>>44878 # 这是线程任务中的 n :>>>> 0 # 1 当前进程的进程号:>>>44875 # 这是线程任务中的 n :>>>> 1 # 2 当前进程的进程号:>>>44876 # 这是线程任务中的 n :>>>> 2 # 3 当前进程的进程号:>>>44879 # 这是线程任务中的 n :>>>> 3 # 4 当前进程的进程号:>>>44877 # 这是线程任务中的 n :>>>> 4 # call_back>>>:<Future at 0x12ca38910 state=finished returned int> # call_back>>>:<Future at 0x12ca392d0 state=finished returned int> # call_back>>>:<Future at 0x12ca39870 state=finished returned int> # call_back>>>:<Future at 0x12ca39780 state=finished returned int> # call_back>>>:<Future at 0x12ca39cf0 state=finished returned int> if __name__ == '__main__': many_steps()
查看异步回调结果
import os from concurrent.futures import ProcessPoolExecutor import time # 构造进程池,指定进程总数 pool = ProcessPoolExecutor(5) # 定义线程任务 def task(n): print(n, f'当前进程的进程号:>>>{os.getpid()}') print(f"这是线程任务中的 n :>>>> {n}") time.sleep(2) return n * 2 # 定义一个异步回调函数 def call_back(n): print(f'call_back>>>:{n} | 返回的结果为:>>>{n.result()}') def many_steps(): task_list = [] for i in range(5): # 提交任务到进程池,并获取到返回值,添加一个异步回调函数 res = pool.submit(task, i).add_done_callback(call_back) print(f'这是 pool的返回值:>>>>{res}') print('this is a main task') # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # 这是 pool的返回值:>>>>None # this is a main task # 0 当前进程的进程号:>>>45050 # 这是线程任务中的 n :>>>> 0 # 1 当前进程的进程号:>>>45049 # 这是线程任务中的 n :>>>> 1 # 2 当前进程的进程号:>>>45046 # 这是线程任务中的 n :>>>> 2 # 3 当前进程的进程号:>>>45047 # 这是线程任务中的 n :>>>> 3 # 4 当前进程的进程号:>>>45048 # 这是线程任务中的 n :>>>> 4 # call_back>>>:<Future at 0x122038910 state=finished returned int> | 返回的结果为:>>>0 # call_back>>>:<Future at 0x122039510 state=finished returned int> | 返回的结果为:>>>2 # call_back>>>:<Future at 0x122039840 state=finished returned int> | 返回的结果为:>>>4 # call_back>>>:<Future at 0x122039ab0 state=finished returned int> | 返回的结果为:>>>6 # call_back>>>:<Future at 0x122039cf0 state=finished returned int> | 返回的结果为:>>>8 if __name__ == '__main__': many_steps()
【五】总结
【1】进程池模版
# 导入模块 from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 构建线程池或进程池 pool_process = ProcessPoolExecutor(5) # 构造异步任务 def task(n): print(f'这是异步传进来的参数 n :>>>> {n}') return n ** 2 def main_process(): task_result_list = [] for i in range(5): # 提交任务 result = pool_process.submit(task, i) print(f'这是异步 {i} 调用的返回结果 :>>>> {result}') # 提交线程任务结果 task_result_list.append(result) # 关闭进程池,等待进程池中所有的任务完成 pool_process.shutdown() # 逐个获取到异步迭代的结果 for task_every in task_result_list: print(f'这是异步调用的返回结果 :>>>> {task_every.result()}') if __name__ == '__main__': main_process() # 这是异步 0 调用的返回结果 :>>>> <Future at 0x110e59030 state=running> # 这是异步 1 调用的返回结果 :>>>> <Future at 0x110e59c60 state=running> # 这是异步 2 调用的返回结果 :>>>> <Future at 0x110e59a20 state=running> # 这是异步 3 调用的返回结果 :>>>> <Future at 0x110e5a140 state=pending> # 这是异步 4 调用的返回结果 :>>>> <Future at 0x110e5a3e0 state=pending> # 这是异步传进来的参数 n :>>>> 0 # 这是异步传进来的参数 n :>>>> 1 # 这是异步传进来的参数 n :>>>> 2 # 这是异步传进来的参数 n :>>>> 3 # 这是异步传进来的参数 n :>>>> 4 # 这是异步调用的返回结果 :>>>> 0 # 这是异步调用的返回结果 :>>>> 1 # 这是异步调用的返回结果 :>>>> 4 # 这是异步调用的返回结果 :>>>> 9 # 这是异步调用的返回结果 :>>>> 16
【2】线程池模版
# 导入模块 from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 构建线程池或进程池 pool_thread = ThreadPoolExecutor(5) # 构造异步任务 def task(n): print(f'这是异步传进来的参数 n :>>>> {n}') return n ** 2 def main_thread(): task_result_list = [] for i in range(5): # 提交任务 result = pool_thread.submit(task, i) print(f'这是异步 {i} 调用的返回结果 :>>>> {result}') task_result_list.append(result) # 关闭进程池,等待进程池中所有的任务完成 pool_process.shutdown() # 逐个获取到异步迭代的结果 for task_every in task_result_list: print(f'这是异步调用的返回结果 :>>>> {task_every.result()}') if __name__ == '__main__': main_thread() # 这是异步传进来的参数 n :>>>> 0 # 这是异步 0 调用的返回结果 :>>>> <Future at 0x12e30ead0 state=finished returned int> # 这是异步 1 调用的返回结果 :>>>> <Future at 0x12e30f190 state=pending> # 这是异步传进来的参数 n :>>>> 1 # 这是异步 2 调用的返回结果 :>>>> <Future at 0x12e30f790 state=pending> # 这是异步传进来的参数 n :>>>> 2 # 这是异步传进来的参数 n :>>>> 3 # 这是异步 3 调用的返回结果 :>>>> <Future at 0x12e33a3e0 state=finished returned int> # 这是异步 4 调用的返回结果 :>>>> <Future at 0x12e30f4c0 state=pending> # 这是异步调用的返回结果 :>>>> 0 # 这是异步调用的返回结果 :>>>> 1 # 这是异步调用的返回结果 :>>>> 4 # 这是异步调用的返回结果 :>>>> 9 # 这是异步传进来的参数 n :>>>> 4 # 这是异步调用的返回结果 :>>>> 16
【3】回调函数模版
# 导入模块 from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 构建线程池或进程池 pool_process = ProcessPoolExecutor(5) pool_thread = ThreadPoolExecutor(5) # 构造异步任务 def task(n): print(f'这是异步传进来的参数 n :>>>> {n}') return n ** 2 # 构造异步调用函数 def call_back(n): print(f'这是异步调用函数中接收到的 :>>>> {n.result()}') return n.result() ** 2 def main_process(): for i in range(5): # 提交任务 result_call_back = pool_process.submit(task, i).add_done_callback(call_back) print(f'这是异步 {i} 调用的返回结果 :>>>> {result_call_back}') def main_thread(): for i in range(5): # 提交任务 result_call_back = pool_thread.submit(task, i).add_done_callback(call_back) print(f'这是异步 {i} 调用的返回结果 :>>>> {result_call_back}') if __name__ == '__main__': main_process() # 这是异步 0 调用的返回结果 :>>>> None # 这是异步 1 调用的返回结果 :>>>> None # 这是异步 2 调用的返回结果 :>>>> None # 这是异步 3 调用的返回结果 :>>>> None # 这是异步 4 调用的返回结果 :>>>> None # 这是异步传进来的参数 n :>>>> 0 # 这是异步传进来的参数 n :>>>> 1 # 这是异步传进来的参数 n :>>>> 2 # 这是异步传进来的参数 n :>>>> 3 # 这是异步传进来的参数 n :>>>> 4 # 这是异步调用函数中接收到的 :>>>> 0 # 这是异步调用函数中接收到的 :>>>> 1 # 这是异步调用函数中接收到的 :>>>> 4 # 这是异步调用函数中接收到的 :>>>> 9 # 这是异步调用函数中接收到的 :>>>> 16 # main_thread() # 这是异步传进来的参数 n :>>>> 0 # 这是异步调用函数中接收到的 :>>>> 0 # 这是异步 0 调用的返回结果 :>>>> None # 这是异步 1 调用的返回结果 :>>>> None # 这是异步传进来的参数 n :>>>> 1 # 这是异步调用函数中接收到的 :>>>> 1 # 这是异步 2 调用的返回结果 :>>>> None # 这是异步传进来的参数 n :>>>> 2 # 这是异步传进来的参数 n :>>>> 3 # 这是异步调用函数中接收到的 :>>>> 9 # 这是异步 3 调用的返回结果 :>>>> None # 这是异步调用函数中接收到的 :>>>> 4 # 这是异步 4 调用的返回结果 :>>>> None # 这是异步传进来的参数 n :>>>> 4 # 这是异步调用函数中接收到的 :>>>> 16