day3.23-通信和线程池、进程池
1. 线程间通信
import random
import time
from threading import Thread,current_thread
from queue import Queue
# 1. 线程间通信
# 同一个进程的多个线程可以直接通信(一个线程可以直接使用另外一个线程中产生的数据)
# 通信原则:使用全局变量
# ====================== 案例一 ========================
# def fun1(x,y):
# global z
# z = x + y
# print(z)
# def fun2():
# print(z)
#
# if __name__ == '__main__':
# t1 = Thread(target=fun1,args=(10,20))
# t1.start()
# t1.join()
# t2 = Thread(target=fun2)
# t2.start()
# ====================== 案例二 ========================
# def download(name):
# all_data.append(f'{name}')
#
# if __name__ == '__main__':
# all_data = []
# names = ['aa','bb','cc']
# for name in names:
# t1 = Thread(target=download,args=(name,))
# t1.start()
# t1.join()
# print(all_data)
# ====================== 案例三 ========================
def download(name):
time.sleep(random.randint(1,3))
q.put(f'{name}')
if __name__ == '__main__':
# 使用队列
# 1)创建队列对象
q = Queue()
names = ['aa','bb','cc']
for name in names:
t1 = Thread(target=download,args=(name,))
t1.start()
# 3)获取队列中的数据
# 队列的get操作有等待功能,如果在执行get的时候队列为空,代码不会报错,而是停留在当前位置,知道队列不为空或者超时为止
for _ in range(3):
print(q.get(timeout=3))
2. 进程间通信
from multiprocessing import Process,Queue
# from queue import Queue 这个队列是线程队列,不支持进程间通信
# 1. 进程间通信
# 不同进程中数据无法直接共享,如果进程间想要通信(数据传输)必须要使用进程队列
def fun1(queue):
print('进程1')
queue.put(30)
def fun2(queue):
print('进程2')
queue.put(20)
if __name__ == '__main__':
x = 100
# 2. 进程队列的使用方法
# 1)创建队列对象
q = Queue()
# 2)将队列对象作为参数传入到进程中
# 如果使用队列的进程和创建队列的进程不一致就必须通过参数传递队列,但是如果是同一个进程直接使用
p1 = Process(target=fun1,args=(q,))
p2 = Process(target=fun2,args=(q,))
p1.start()
p2.start()
# 3)在任意进程中使用队列获取数据
print(q.get())
print(q.get())
3. 线程池
import random
import time
from threading import Thread,current_thread
# 倒入线程池(线程池执行者)对应的类
from concurrent.futures import ThreadPoolExecutor
# 1. 线程池
'''
一个线程池中可以有多个线程,并且可以添加多个任务(任务的数量可以比线程的数量多),
线程池会自动给线程池的线程分配任务,直到所有的任务都完成.
'''
def download(name):
# time.sleep(random.randint(2,4))
print(f'{name}数据',current_thread())
if __name__ == '__main__':
names = [f'{x}电影' for x in range(20)]
# 方法一
# for name in names:
# t = Thread(target=download,args=(name,))
# t.start()
# 方法二:使用线程池
# 1. 创建线程池:ThreadPoolExecutor(线程数)
pool = ThreadPoolExecutor(5)
# 2. 添加任务
# 1)人物一个一个添加到线程池中:pool.submit(函数名,变量1,变量2,...)
# 人物对应的函数只有一个参数
# for name in names:
# pool.submit(download,name)
# 2)同时添加多个任务 - 任务对应的函数有且只有一个参数
# 线程池对象.map(函数,实参对应的序列)
pool.map(download,names)
# 3. 关闭线程池并且等待线程池任务结束
# 关闭线程池指的是停止往线程池中添加任务
# 线程池关闭前可以随时添加任务
# pool.shutdown()
4. 进程池
from multiprocessing import Pool, current_process
import time
from random import randint
def download(name):
time.sleep(randint(2, 6))
print(f'{name}数据', current_process())
def func1(x, y):
print(x, y)
if __name__ == '__main__':
# 1. 创建进程池对象
pool = Pool(5)
# 2. 添加任务
# 1) 一次添加一个任务
# pool.apply_async(download, args=('肖申克的救赎',))
# pool.apply_async(func1, args=(100, 200))
# for x in range(10):
# pool.apply_async(download, args=(f'电影{x}',))
# 2) 同时添加多个任务
pool.map_async(download, ['电影1', '电影2', '电影3'])
# 3. 关闭进程池(通过async方式添加的任务,必须在任务添加结束后依次执行close和join操作,任务才会启动)
pool.close()
pool.join()
作业