队列的认识:
- Python的Queue模块中提供了同步的、线程安全的队列类,包括:FIFO(先入先出)队列QueueLIFO、(后入先出)队列LifoQueue、优先级队列PriorityQueue,这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步
- 队列中数据添加和获取 已经加了锁(所有用队列来存储多线程公用的全局数据,不会出现资源竞争的问题)
队列的的类型:
- (先入先出队列) Queue , 快速使用:from queue import Queue
- (后入先出队列)LifoQueue , 快速使用:from queue import LifoQueue
- 优先级队列 PriorityQueue , 快速使用:from queue import PriorityQueue
队列中的元素为元祖类型:(优先级,数据)------- 例如:(99,33333)
类型一:(先入先出) Queue队列
顾名思义:先入先出,先进入的数据,先获取出来
初始化Queue()对象时,若括号中没有指定最大可接收的消息数量,或数量为负值,代表可接受的消息数量没有上限
例如:q=Queue(3) 表示最大可接收数量为3
例如:q=Queue(0) 表示最大可接收数量没有上限
# 创建一个队列对象
q = Queue(3) # 最大只能添加三条数据
往队列中添加数据的方法:Queue.put(item)
语法: put(self, item, block=True, timeout=None)
参数1 ———》 item: 数据
参数2 ———》 block: 如果队列已满是否等待;
参数3 ———》 timeout: 等待的超时时间,超时后报错
# 1. 往队列中添加数据的方法: put
q.put('111')
q.put('222')
q.put('333')
# 添加第四条数据
# 参数:block表示是否等待,timeout表示等待时间
q.put('444',block=False,timeout=3) # 如果队列已满,则会进入堵塞状态(等待)
获取队列中数据的方法:Queue.get()
语法: get(self, item, block=True, timeout=None)
参数1 ———》 item: 数据
参数2 ———》 block: 如果队列已满是否等待;
参数3 ———》 timeout: 等待的超时时间,超时后报错
# 2. 获取队列中数据的方法:get
q.get() # ======> 取出来的数据为 111
q.get() # ======> 取出来的数据为 222
q.get() # ======> 取出来的数据为 333
# 添加第四条数据
# 参数:block表示是否等待,timeout表示等待时间
print(q.get(block=False)) # 如果队列为空,则会进入堵塞状态(等待)
判断队列是否满了:Queue.full()
语法: 如果队列满了,返回True, 反之False
# 3. full:判断队列是否已满
print(q.full()) # 满的就是True ,反之
判断队列是否为空:Queue.empty()
语法: 如果队列为空,返回True, 反之False
# 4. empty:判断队列是否为空
print(q.empty()) # 为空的就是True ,反之
返回队列消息数量:Queue.qsize()
语法:返回当前队列包含的消息数量
# 5. 取队列中的数据量
print(q.qsize())
Queue.task_done()
语法:在完成一项工作之后,使用Queue.task_done()方法可以向队列发送一个信号,表示该任务执行完毕
Queue.join()
- 语法:实际上意味着等到队列中所有的任务(数据)执行完毕之后,再往下,否则一直等待
- 注意点:join()是判断的依据,不单单指的是队列中没有数据,数据get出去之后,要使用task_done()向队列发送一个信号,表示该任务执行(数据使用)完毕
- 队列中task_done方法和join 是相互配合使用的,缺一不可
1.在使用线程实现子线程执行完后在执行主线程
# 初始化对象
q = Queue()
for i in range(15):
q.put('数据{}'.format(i)) # 添加队列数据
def work(data):
"""线程执行的工作函数"""
for i in range(5):
time.sleep(random.randint(1, 4)) # 随机等待时间
print("数据data:{}处理完毕".format(data))
def main():
"""使用线程等待的方法"""
ts =[]
for i in range(10):
data = q.get()
t1 = Thread(target=work, args=(data,))
t1.start()
ts.append(t1)
for i in ts:
i.join()
print("------等待线程中所有的数据处理完毕再往下执行-----------")
2.使用队列来实现子线程执行完后在执行主线程
# 初始化对象
q = Queue()
for i in range(15):
q.put('数据{}'.format(i)) # 添加队列数据
def work(data):
"""线程执行的工作函数"""
for i in range(5):
time.sleep(random.randint(1, 4)) # 随机等待时间
print("数据data:{}处理完毕".format(data))
# 给队列发送一个信号,已经处理好了
q.task_done()
def main():
"""使用队列等待的方法"""
for i in range(10):
data = q.get() # 获取数据
t1 = Thread(target=work, args=(data,)) # 设置线程
t1.start() # 启动线程
# 等待队列中所有的任务执行完毕(数据处理完毕)
q.join()
print("------等待线程中所有的数据处理完毕再往下执行-----------")
4.类型二和三:(后入先出) LifoQueue 队列 和 (优先级队列) PriorityQueue
三种类型的队列,Queue队列、 LifoQueue 队列 、PriorityQueue 方法都是一样,唯一区别是数据的的取出不一样
顾名思义:
后入先出,后面进入的数据,先获取出来
优先级队,根据排序优先级,先获取出来
初始化对象时,若括号中没有指定最大可接收的消息数量,或数量为负值,代表可接受的消息数量没有上限
例如:q=LifoQueue (3) 表示最大可接收数量为3
例如:q=LifoQueue(0) 表示最大可接收数量没有上限
# 创建一个队列对象
q = LifoQueue(3) # 最大只能添加三条数据
q = PriorityQueue() # 最大可接收数量没有上限
往队列中添加数据的方法:LifoQueue .put(item) / PriorityQueue.put(item)
语法: put(self, item, block=True, timeout=None)
参数1 ———》 item: 数据
参数2 ———》 block: 如果队列已满是否等待;
参数3 ———》 timeout: 等待的超时时间,超时后报错
# LifoQueue 队列
# 1. 往队列中添加数据的方法: put
q.put('111')
q.put('222')
q.put('333')
# 添加第四条数据
# 参数:block表示是否等待,timeout表示等待时间
q.put('444',block=False,timeout=3) # 如果队列已满,则会进入堵塞状态(等待)
# PriorityQueue队列
# 1. 往队列中添加数据的方法: put
q.put((77,'111')) # 队列中的元素为元祖类型)
q.put((4,'222'))
q.put((888,'333'))
获取队列中数据的方法:LifoQueue .get(item) / PriorityQueue.get(item)
语法: get(self, item, block=True, timeout=None)
参数1 ———》 item: 数据
参数2 ———》 block: 如果队列已满是否等待;
参数3 ———》 timeout: 等待的超时时间,超时后报错
# 2. 获取队列中数据的方法:get
q.get() # ======> 取出来的数据为 111
q.get() # ======> 取出来的数据为 222
q.get() # ======> 取出来的数据为 333
# 添加第四条数据
# 参数:block表示是否等待,timeout表示等待时间
print(q.get(block=False)) # 如果队列为空,则会进入堵塞状态(等待)
一 、进程模块的详细使用
什么是进程:
一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元
进程的状态
- 工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
- 就绪状态:运行的条件都已经满足了,随时可以给操作系统调度执行
- 执行状态:cpu正在执行其功能
- 等待状态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
进程和线程有什么区别
- 从功能来说:
进程是能够能够完成多任务,比如 在一台电脑上能够同时运行多个软件
线程是能够完成多任务,比如 一个QQ中的多个聊天窗口- 从定义上来说:
一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),故对它的调度所付出的开销就会小得多, 能更高效的提高系统内多个程序间并发执行的程度
创建进程对象: multiprocessing .Process (target=任务函数)
其中参数target指定线程执行的任务 (函数)
进程参数的使用
内置的进程的模块是:multiprocessing 模块里的 Process 类
multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情
快速使用:from multiprocessing import Process
Process 类有以下参数:
1、target参数: 指定任务函数
import time
from multiprocessing import Process
def func1():
for i in range(5):
print("-正在做事情1------")
time.sleep(1)
# 创建一个线程对象
aa = Process(target=func1)
2、name参数: 设置进程名
# 创建一个进程对象
aa = Process(target=func1,name="henry")
3.、args参数: 给任务函数传参(参数传递的是元祖类型)
def func1(aa):
for i in range(5):
print("---{}---正在做事情1------".format(aa)
time.sleep(1)
# 创建一个进程对象
aa = Process(target=func1,args=('张三',))
4、kwargs参数:给任务函数传参(参数传递的是字典类型)
def func1(aa):
for i in range(5):
print("---{}---正在做事情1------".format(aa)
time.sleep(1)
# 创建一个进程对象
aa = Process(target=func1,kwargs={'aa': "李四"})
5、daemon参数:设置是否作为守护进程(bool值)
- 设置子进程守护主进程执行(主进程结束,守护进程自动结束)
- 如果没有设置守护进程,主进程跑完,子进程没有跑完,还会继续跑下去,不会有影响
- 如果设置了守护进程,主进程跑完,子进程没有跑完,当前进程全部结束(包括子进程,不管是否跑完)
- 如果多个子进程,一个设置了守护进程,一个没有设置守护进程,主进程结束,子进程还会继续跑下去,不会有影响
def func1(aa):
for i in range(5):
print("---{}---正在做事情1------".format(aa))
# print("---正在做事情1------")
time.sleep(1)
def func2(aa):
for i in range(6):
print("----{}--正在做事情2------".format(aa))
time.sleep(1)
# 创建一个进程对象
t1 = Process(target=func1, args=('张三',),daemon=True) # 设置守护进程
t2 = Process(target=func2, kwargs={'aa': "李四"},daemon=True) # 设置守护进程
# 启动进程执行
t1.start()
t2.start()
time.sleep(2)
print("----主线程执行结束-----------")
进程方法的使用
Process类提供了以下方法:
1、start()方法: 启动进程执行
# 启动线程执行
t1.start()
t2.start()
2、join([time]): 设置主进程等待的时间
- 设置主进程会等待time秒后再往下执行,不设置time,则默认为子进程结束,多个子进程之设置的值会叠加
- 多个子进程同时使用join设置的时间会叠加
def func2():
for i in range(6):
print("------正在做事情2------")
time.sleep(1)
# 创建一个进程对象
t1 = Process(target=func2) # 子进程t1
# # 子进程t1启动执行
t1.start()
# 主进程等待时间
t1.join() # 让主进程等待t1执行完,再往下执行
# 主进程等待子线程执行完
for i in range(10):
print("主进程全部执行完成——————————————————————————")
3、run方法 :进程接收到的任务函数,最终是在run方法里面执行的(进程执行的任务)
4、isDaemon: 判断是否为守护线程
5、isAlive: 判断线程支持存活(处于执行状态)
6、is_alive:判断线程支持存活(处于执行状态)
7、getName:获取线程名
注意点
使用多进程时,要确保程序的入口在if name == ‘main’:中