多进程和多线程
多线程
import time
from datetime import datetime
from threading import Thread
# 进程默认有一个线程,这个线程叫主线程;其他的线程都叫子线程
# Python中的threading模块中Thread类的对象就是线程对象(程序中需要多少个线程就创建多少个Thread类或者它的子类的对象)
def download(name):
print(f'{name}开始下载!{datetime.now()}')
time.sleep(3)
print(f'{name}下载结束!{datetime.now()}')
# 1.创建线程对象
# Thread(target=函数, args=参数)
# 函数 - 传一个函数,这个函数就是需要在子线程中调用的函数
# 参数 - 传一个元组,默认是();元组中的元素就是在调用函数的时候需要传递的实参
t1 = Thread(target=download, args=('海王',))
t2 = Thread(target=download, args=('触不可及',))
t3 = Thread(target=download, args=('星际穿越',))
# 2.启动线程 - 在子线程中执行任务
# 线程对象.start()
t1.start()
t2.start()
t1.join()
t2.join()
t3.start()
# 1.join的用法
"""
线程对象.join()
代码段
代码段会在线程对象对应的线程结束后执行
"""
f_names = ['海王', '触不可及', '星际穿越']
线程池
from threadpool import ThreadPool, makeRequests
import time
from datetime import datetime
from threading import current_thread, Thread
from queue import Queue
q = Queue()
def download(name):
print(f'{name}开始下载!', datetime.now())
print(current_thread())
time.sleep(1)
print(f'{name}下载结束!', datetime.now())
q.put(name)
def save():
print('============开始保存===========')
num = 0
while True:
print('==保存数据的线程==', current_thread())
result = q.get()
if result == 'end':
break
print(f'=====保存{result}成功')
# 1.创建任务列表
# makeRequests(任务对应的函数,参数列表)
# 注意:
# 1)任务函数有且只有一个参数
# 2)参数列表中元素的个数决定了任务列表中任务的个数
tasks = makeRequests(download, [f'电影{x}' for x in range(100)])
# tasks2 = makeRequests(save, [0])
# print(tasks)
# 2.创建线程池对象
# ThreadPool(线程的数量)
pool = ThreadPool(10)
# 3.在线程池中添加任务
# 线程池对象.putRequest(任务对象)
for task in tasks:
pool.putRequest(task)
# for task in tasks2:
# pool.putRequest(task)
# 在一个独立线程中添加保存任务
t = Thread(target=save)
t.start()
# 4.执行和等待
pool.wait()
q.put('end')
线程之间的数据安全
lock
和Rlock
使用方法
from threading import Thread, current_thread, Lock, RLock
"""
1)保证一个数据对应一个锁对象
锁对象 = Lock()
2)线程在第一次操作数据前加锁
锁对象.acquire()
3)线程在结束数据操作后解锁
锁对象.release()
"""
"""
Lock也可用这种方法
1)保证一个数据对应一个锁对象
锁对象 = RLock()
2)将对数据进行操作的代码放到锁的范围内
with 锁对象:
操作数据的代码
"""
"""
这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
"""
多进程
from multiprocessing import Process
import time
from datetime import datetime
# 多进程和多线程的区别:
# 多线程只是增加线程数量,不会增加运行内容(只是在车间中添加工人);多个线程可以修改同一个全局变量
# 多进程会增加线程数量,也会增加运行内容(添加新的车间,每个车间拥有一个工人);不能在一个中取修改另一个进程的数据
def download(name):
print(f'{name}开始下载!', datetime.now())
time.sleep(1)
print(f'{name}下载结束!', datetime.now())
if __name__ == '__main__':
# 1.创建进程对象
p1 = Process(target=download, args=('让子弹飞',))
p2 = Process(target=download, args=('赌神',))
p3 = Process(target=download, args=('活着',))
# 2.开始执行进程中的任务
p1.start()
p2.start()
p3.start()
进程池
from multiprocessing import Pool
import time
from datetime import datetime
from threadpool import ThreadPool, makeRequests
from queue import Queue
from threading import current_thread
def download(name):
print(f'{name}开始下载!')
# print(current_thread())
time.sleep(1)
print(f'{name}下载结束!')
def download_movie_thread(num):
# q = Queue()
# q.put(num)
# if q.qsize() == 10:
tasks = makeRequests(download, num)
pool1 = ThreadPool(10)
for x in tasks:
pool1.putRequest(x)
pool1.wait()
if __name__ == '__main__':
# 1.创建进程池
# Pool(进程数量)
list1 = [f'电影{x}' for x in range(200)]
list2 = []
for i in range(0, 200, 10):
list2.append(list1[i:i + 10])
start = time.time()
pool = Pool(3)
# 2.添加任务(任务添加完成后会自动启动)
# 1)一次性添加多个任务
# 进程池对象.map(函数,参数列表)
# pool.map(download_movie_thread, [])
# 2)一次添加一个任务
pool.map(download_movie_thread, list2)
# apply() - 添加的任务和主进程中的任务同步执行
# apply_async() - 添加的任务和主进程中的任务异步执行
# pool.apply(download, ('肖申克的救赎',))
# 3.关闭线程池
# 进程池关闭后不能再往进程池中添加任务
pool.close()
# 4.等待
pool.join()
end = time.time()
print('结束====================', end-start)