【11.0】进程池和线程池
【一】TCP实现并发的效果的原理
- 每开设一个客户端,就会有一个服务端服务
【1】服务端
from socket import *
from threading import Thread
def server_create(IP, PORT):
server = socket()
server.bind((IP, PORT))
server.listen(5)
while True:
conn, addr = server.accept()
t = Thread(target=conn_communication, args=(conn,))
def conn_communication(conn):
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
break
print(data.decode('utf8'))
conn.send(data.upper())
except Exception as e:
print(e)
break
conn.close()
def main():
IP = '127.0.0.1'
PORT = 8086
t = Thread(target=server_create, args=(IP, PORT,))
t.start()
if __name__ == '__main__':
main()
【2】客户端
from socket import *
def client_create(IP, PORT):
client = socket()
client.connect((IP, PORT))
while True:
word = b'hello world'
client.send(word)
msg = client.recv(1024)
print(msg)
if __name__ == '__main__':
IP = '127.0.0.1'
PORT = 8086
client_create(IP, PORT)
【3】小结
- 无论是开设进程还是开设线程,都需要消耗资源
- 只不过开始线程消耗的资源比开始进程相对少一些
- 硬件的开发速度永远赶不上软件开发速度
- 我们的宗旨是保证计算机硬件正常工作的情况下最大程度的利用它
【二】什么是池
- 池是用来保证计算机硬件安全的情况下最大限度的利用计算机
- 池降低了程序的运行效率,但是保证了计算机硬件的安全,从而保证程序的正常运行
【三】线程池
【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('this 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()
【3】查看异步回调结果
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
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17982401