队列
是什么,请自行查阅from queue import Queue
# 创建队列
# -- 限制队中最多有 maxsize 个元素
# -- 如果省略参数,默认元素个数无限制
q = Queue(100)
q1 = Queue()
# 元素入队
q.put(1)
q.put(True)
q.put('abc')
# 队列的大小
print(q.qsize())
# 判断队满
print(q.full())
# 判断队空
print(q.empty())
# 元素出队
# 注意:如果队空,取元素时,会陷入阻塞状态,知道再往队中加入数据为止【***】
while not q.empty():
print(q.get())
'''
1. 一个进程可以有多个线程,但是必须有一个主线程
2. 进程之间互不影响,资源不共享
3. 线程之间,资源可以共享,共享的是线程所属的进程的内容
4. 线程必须依赖于进程存在
'''
from threading import Thread
def add(n1, n2):
print('结果为:' + n1 + n2)
def main():
# 创建一个线程
# -- target 函数的名称
# -- args 以元组的形式,传入函数所需的参数
t = Thread(target=add, args=(1, 2,))
# 开启线程
t.start()
if __name__ == '__main__':
main()
'''
1. 通过继承 Thread类 创建线程的步骤
(1) 定义一个类
(2) 继承 Thread类
(3) 重写 run() 方法
(4) 在 run() 方法中写逻辑代码
2. 注意事项
(1) 子类继承 Thread类 后,实例化对象时,会自动执行父类中的 run()方法
所以我们可以重写 run(),然后在 run() 中执行我们自己的代码
(2) 一个子类继承了 Thread类,那么在对线程执行任何其他操作之前
它必须确保已调用基类的构造函数
-- 比如:传参时,需要调用的父类的构造函数
'''
from threading import Thread
class MyThread(Thread):
# 构造函数
def __init__(self, n1, n2):
# 调用父类的构造函数:第一种方法
# threading.Thread.__init__(self)
# 调用父类的构造函数:第二种方法
super().__init__()
self.n1 = n1
self.n2 = n2
# 重写 run() 方法
def run(self):
print('线程的名称:' + self.name)
print(self.n1 + self.n2)
def main():
# 实例化对象的过程,就是在创建线程
t1 = MyThread(1, 1)
# 设置线程的名称
t1.setName('t1')
# 开启线程
t1.start()
if __name__ == '__main__':
main()
# 加锁之前
# ----------------------------------------------------------
from threading import Thread
num = 0 # 声明共享资源
def Jia():
# 标注使用共享的资源
global num
# 主逻辑代码
for i in range(10000000):
num+=1
print(num)
def main():
# 创建线程
t1 = Thread(target=Jia)
t2 = Thread(target=Jia)
t3 = Thread(target=Jia)
# 开启线程
t1.start()
t2.start()
t3.start()
if __name__ == '__main__':
main()
# 加锁之后
# ----------------------------------------------------------
from threading import Thread
from threading import Lock
lock = Lock() # 声明锁,要保证相关的线程使用的是同一把锁
num = 0 # 声明共享资源
def Jia(lock):
# 加锁
lock.acquire()
# 标注使用共享的资源
global num
# 主逻辑代码
for i in range(10000000):
num+=1
print(num)
# 释放锁
lock.release()
def main():
# 创建线程
t1 = Thread(target=Jia, args=(lock,))
t2 = Thread(target=Jia, args=(lock,))
t3 = Thread(target=Jia, args=(lock,))
# 开启线程
t1.start()
t2.start()
t3.start()
if __name__ == '__main__':
main()
阻塞当前所在的线程
,只有当执行 join() 的线程结束之后,才会解除阻塞print('结束了')
,本意是想要在fn
函数执行完之后,再输出结束了
,但是因为主线程和t1线程是同步的,他们在同时执行,所以print('结束了')
的输出位置不一定是最后面,可能是在fn
执行一半的时候就输出结束了
t1线程
调用了join()
,阻塞了当前所在线程,即阻塞了主线程,所以主线程需要等t1线程
结束后才可以继续执行主线程的内容,故实现了print('结束了')
在fn
执行完后在输出内容的需求# 阻塞前:也就是不调用 join()
# ----------------------------------------------------------
import time
from threading import Thread
def fn():
for i in range(10):
print(i)
time.sleep(1.5)
def main():
t1 = Thread(target=fn)
t1.start()
print('结束了')
if __name__ == '__main__':
main()
# 阻塞后:调用了 join()
# ----------------------------------------------------------
import time
from threading import Thread
def fn():
for i in range(10):
print(i)
time.sleep(1.5)
def main():
t1 = Thread(target=fn)
t1.start()
t1.join()
print('结束了')
if __name__ == '__main__':
main()
'''
1. 进程分为主进程、守护进程、非守护进程
2. 守护、非守护是相对于主进程 而言的
3. 守护进程,可以理解为不重要的进程,当主进程结束后,守护进程会强制结束
4. 非守护进程,是比守护进程重要的进程,当主进程结束后,守护进程不会被强制结束
'''
# t1进程是非守护进程:t1进程会陷入死循环
# ----------------------------------------------------------
from threading import Thread
def fn():
while True:
print(1)
def main():
t1 = Thread(target=fn)
t1.start()
print('结束了')
if __name__ == '__main__':
main()
# t1进程是守护进程:t1进程会因为主进程的结束,被强制结束
# ----------------------------------------------------------
from threading import Thread
def fn():
while True:
print(1)
def main():
t1 = Thread(target=fn)
t1.start()
t1.setDaemon(True) # 设置为True时,说明此进程是"守护进程"【默认是False】
print('结束了')
if __name__ == '__main__':
main()
一定要在后面的代码中仔细思考一下,尤其是阶段5的代码
# Queue.join()
'''
当生产者生产结束时,先阻塞生产者线程,只有当消费者发出已经消费完队中产品时,才解除阻塞
'''
# Queue.task_done()
'''
消费者消费一个队中的产品,就向生产者发送一次信息
当消费完队中信息之后,也向生产者发送信息,并发出已经消费完的提示,提示生产者可以解除生产者线程的阻塞了
'''
from queue import Queue
from threading import Thread
# 生产者
def produce(q):
for i in range(1, 11):
q.put(i)
print(f'生产产品——{i}')
# 消费者
def consumer(q):
while True:
tmp = q.get()
print(f'消费产品——{tmp}')
# 主进程
def main():
q = Queue()
pro = Thread(target=produce, args=(q,))
con = Thread(target=consumer, args=(q,))
pro.start()
con.start()
if __name__ == '__main__':
main()
from queue import Queue
from threading import Thread
# 生产者
def produce(q):
for i in range(1, 11):
q.put(i)
print(f'生产产品——{i}')
# 消费者
def consumer(q):
while True:
tmp = q.get()
print(f'消费产品——{tmp}')
# 主进程
def main():
q = Queue()
pro = Thread(target=produce, args=(q,))
con = Thread(target=consumer, args=(q,))
con.setDaemon(True) # 设置守护线程
pro.start()
con.start()
if __name__ == '__main__':
main()
from queue import Queue
from threading import Thread
# 生产者
def produce(q):
for i in range(1, 11):
q.put(i)
print(f'生产产品——{i}')
q.join() # 阻塞生产者线程,只有接收到消费者发送来的已经消费了最后一个产品的时候,才解除阻塞
# 消费者
def consumer(q):
while True:
tmp = q.get()
print(f'消费产品——{tmp}')
q.task_done() # 向生产者发送消息,告诉生产者我已经消费了一个产品
# 主进程
def main():
q = Queue()
pro = Thread(target=produce, args=(q,))
con = Thread(target=consumer, args=(q,))
con.setDaemon(True)
pro.start()
con.start()
if __name__ == '__main__':
main()
针对阶段2仅添加了两行代码
分析:
from queue import Queue
from threading import Thread
# 生产者
def produce(q):
for i in range(1, 11):
q.put(i)
print(f'生产产品——{i}')
q.join() # 阻塞生产者线程,只有接收到消费者发送来的已经消费了最后一个产品的时候,才解除阻塞
# 消费者
def consumer(q):
while True:
tmp = q.get()
print(f'消费产品——{tmp}')
q.task_done() # 向生产者发送消息,告诉生产者我已经消费了一个产品
# 主进程
def main():
q = Queue()
pro = Thread(target=produce, args=(q,))
con = Thread(target=consumer, args=(q,))
con.setDaemon(True)
pro.start()
con.start()
print('结束了')
if __name__ == '__main__':
main()
与阶段3相比,仅在主线程中添加一行输出语句
from queue import Queue
from threading import Thread
# 生产者
def produce(q):
for i in range(1, 11):
q.put(i)
print(f'生产产品——{i}')
q.join() # 阻塞生产者线程,只有接收到消费者发送来的已经消费了最后一个产品的时候,才解除阻塞
# 消费者
def consumer(q):
while True:
tmp = q.get()
print(f'消费产品——{tmp}')
q.task_done() # 向生产者发送消息,告诉生产者我已经消费了一个产品
# 主进程
def main():
q = Queue()
pro = Thread(target=produce, args=(q,))
con = Thread(target=consumer, args=(q,))
con.setDaemon(True)
pro.start()
con.start()
pro.join() # 阻塞当前所在的线程
print('结束了')
if __name__ == '__main__':
main()
与阶段4相比,仅添加一句代码,以达到阻塞主线程的需求