提示:文章基本为自己实验总结,仅参考,可能有不严谨的地方请读者们见谅
前言
线程优先级队列( Queue):
Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。
Python线程
提示:以下是本篇文章正文内容,下面案例可供参考
进程就是正在运行的程序的实例。
进程是具有一定独立功能的程序,它会关于某个数据进行运行活动。
进程是一个实体,都会有自己的地址空间,里面有文本区域,数据区域,堆栈。
一、 Queue队列基本基础
为了方面之后进程的数据交互,所以要学习队列
Queue模块中的常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item, block=True, timeout=None) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当 Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作
put_nowait
q.put_nowait("x4")#可以用put_nowait,如果队列满了就不会堵塞,但是会报错。。。
full()和empty()
print(q.full())#判断一下队列是否满了
print(q.empty())#判断一下队列是为空
实例如下👇
import time,os,random
from multiprocessing import Process,Queue
def main():
q = Queue(3)#定义一个叫q的队列,队列容量为3
q.put("x1")
q.put("x2")
q.put("x3")
# q.put("x4"),如果队列满了程序就会停在这里,等待数据被人取走,再将数据放入队列
try:
q.put_nowait("x4")#可以用put_nowait,如果队列满了就不会堵塞,但是会报错。。。
except:
print("队列满了,不能再放了")
print(q.full())#判断一下队列是否满了
print(q.get())
print(q.get())
print(q.get())
print(q.empty())#判断一下队列是为空
pass
if __name__=='__main__':
main()
pycharm显示结果为:
队列满了,不能再放了
True
x1
x2
x3
True
Process finished with exit code 0
二、进程间传递数据—队列
使用queue实现进程之间的信息传递
在编程中,我们经常需要在不同的进程之间传递数据。就像我们在梦中经历的事件可以在清醒状态下回忆一样,进程之间也需要一个类似的中介来共享数据。这个中介就是队列(Queue)对象,在Python的multiprocessing包中有一个专门的Queue类用于实现这个目的。
你可以把队列想象成排队的人群,按照先来后到的原则,数据被依次放入队列中。不同的进程可以从队列中取出数据,并将自己的数据放入其中,以便其他进程使用。这样,进程之间就能够方便地共享数据了。
使用队列作为中介的好处是,它提供了一种安全和同步的方式来传递数据。多个进程可以同时读写队列,而不需要担心数据错乱或冲突的问题。队列会按照先进先出的原则确保数据被正确地交换和传递。
总结来说,队列是进程之间数据传递的一种有效方式。它类似于一个中介,让不同的进程能够按照一定规则共享数据,实现数据交换和通信。
以下用三个实例说明进程队列间传递数据
生产者和消费者模型
实例一
import time,os,random
from multiprocessing import Process,Queue
def customer(q):
while True:
res = q.get()
if res is None: break
time.sleep(random.randint(1,3))
print("%s 吃了 %s"%(os.getpid(),res))
def producer(q):
for i in range(10):
time.sleep(random.randint(2,4))
res = "包子 %s"%(i)
q.put(res)
print("%s生产了%s"%(os.getpid(),res))
q.put(None)
def main():
q = Queue()
p1 = Process(target=customer,args=(q,))
p2 = Process(target=producer,args=(q,))
p1.start()
p2.start()
print("主进程开始")
pass
if __name__=='__main__':
main()
运行结果为:
实例二
import time,os,random
from multiprocessing import Process,Queue
#结束信号None,不一定只能由生产者去发,可以主进程等生产者完成后由主进程去发
def customer(q):
while True:
res = q.get()
if res is None: break
time.sleep(random.randint(1,3))
print("%s 吃了 %s"%(os.getpid(),res))
def producer(q):
for i in range(10):
time.sleep(random.randint(2,4))
res = "包子 %s"%(i)
q.put(res)
print("%s生产了%s"%(os.getpid(),res))
def main():
q = Queue()
p1 = Process(target=customer,args=(q,))
p2 = Process(target=producer,args=(q,))
p1.start()
p2.start()
p1.join()
q.put(None)
print("主进程开始")
pass
if __name__=='__main__':
main()
运行结果为:
28852生产了包子 0
23028 吃了 包子 0
28852生产了包子 1
23028 吃了 包子 1
28852生产了包子 2
28852生产了包子 3
23028 吃了 包子 2
28852生产了包子 4
23028 吃了 包子 3
28852生产了包子 5
23028 吃了 包子 4
23028 吃了 包子 5
28852生产了包子 6
23028 吃了 包子 6
28852生产了包子 7
23028 吃了 包子 7
28852生产了包子 8
28852生产了包子 9
23028 吃了 包子 8
23028 吃了 包子 9
实例三:多个生产者和消费者
import time,os,random
from multiprocessing import Process,Queue
def customer(q):
while True:
res = q.get()
if res is None: break
time.sleep(random.randint(1,3))
print("%s 吃了 %s"%(os.getpid(),res))
def producer(name,q):
for i in range(10):
time.sleep(random.randint(2,4))
res = "%s 的 %s号"%(name,i)
q.put(res)
print("%s生产了%s"%(os.getpid(),res))
def main():
q = Queue()
#多个厨师
p1 = Process(target=producer,args=("包子",q,))
p2 = Process(target=producer,args=("牛肉",q,))
p3 = Process(target=producer,args=("骨头",q,))
#多个消费者
c1 = Process(target=customer,args=(q,))
c2 = Process(target=customer,args=(q,))
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
#必须保证生产者都处理完毕,才能发出结束信号
p1.join()
p2.join()
p3.join()
#有几个消费者发出几个结束信号
q.put(None)
q.put(None)
q.put(None)
print("主进程开始")
pass
if __name__=='__main__':
main()
运行结果为:
三、共享进程队列
from multiprocessing import Process,Queue,JoinableQueue
JoinableQueue:
是一个创建可连接的共享进程队列,它其实相当于Queue的一个对象队列形式,它允许项目的使用者通知生产者:项目已经被处理了。
JoinableQueue 主要用于生产者消费者模型,解决多个消费者在消费完队列中所有任务后结束消费进程
JoinableQueue 却别于 Queue的两个主要方法:
1、task_done() 使用此方法发出当前队列中取出来的项目已经被处理(消费者调用此方法)
2、join() 生产者调用此方法进行阻塞,直到JoinableQueue 中的每个项目都收到了task_done()处理完成的消息 才会停止阻塞
实例
本例中较重要的两个函数👇
q.task_done()#向q.join发送一次信号,证明数据已经被取走了
q.join()#生产完毕,使用这个方法进行阻塞,直到队列中所有内容被处理
import time,os,random
from multiprocessing import Process,Queue,JoinableQueue
def customer(q):
while True:
res = q.get()
time.sleep(random.randint(1,3))
print("%s 吃了 %s"%(os.getpid(),res))
q.task_done()#向q.join发送一次信号,证明数据已经被取走了
def producer(name,q):
for i in range(10):
time.sleep(random.randint(2,4))
res = "%s 的 %s号"%(name,i)
q.put(res)
print("%s生产了%s"%(os.getpid(),res))
q.join()#生产完毕,使用这个方法进行阻塞,直到队列中所有内容被处理
def main():
q = JoinableQueue
#定义生产者们
p1 = Process(target=producer, args=("包子", q))
p2 = Process(target=producer, args=("羊肉", q))
p3 = Process(target=producer, args=("猪肉", q))
#定义消费者们
c1 = Process(target=customer,args=(q,))
c2 = Process(target=customer, args=(q,))
#设置为守护进程
c1.daemon = True
c2.daemon = True
#开始
p_1 = [p1,p2,p3,c1,c2]
for p in p_1:
p.start()
p1.join()
p2.join()
p3.join()
print("主进程")
pass
if __name__=='__main__':
main()
本实例流程白话简介:
运行结果为:
17392生产了包子 的 0号
22716生产了猪肉 的 0号
13116 吃了 猪肉 的 0号
7580生产了羊肉 的 0号
17392生产了包子 的 1号22716生产了猪肉 的 1号
23616 吃了 包子 的 0号
13116 吃了 羊肉 的 0号
7580生产了羊肉 的 1号
23616 吃了 包子 的 1号
13116 吃了 猪肉 的 1号
22716生产了猪肉 的 2号
13116 吃了 猪肉 的 2号
17392生产了包子 的 2号
23616 吃了 羊肉 的 1号
7580生产了羊肉 的 2号
13116 吃了 包子 的 2号23616 吃了 羊肉 的 2号
22716生产了猪肉 的 3号
13116 吃了 猪肉 的 3号
17392生产了包子 的 3号
7580生产了羊肉 的 3号
23616 吃了 包子 的 3号
13116 吃了 羊肉 的 3号
17392生产了包子 的 4号22716生产了猪肉 的 4号
7580生产了羊肉 的 4号
23616 吃了 包子 的 4号
13116 吃了 猪肉 的 4号
17392生产了包子 的 5号22716生产了猪肉 的 5号
7580生产了羊肉 的 5号
13116 吃了 包子 的 5号
23616 吃了 羊肉 的 4号
7580生产了羊肉 的 6号
13116 吃了 猪肉 的 5号
17392生产了包子 的 6号
22716生产了猪肉 的 6号
23616 吃了 羊肉 的 5号
7580生产了羊肉 的 7号
13116 吃了 羊肉 的 6号
17392生产了包子 的 7号
7580生产了羊肉 的 8号23616 吃了 包子 的 6号
22716生产了猪肉 的 7号
13116 吃了 猪肉 的 6号
23616 吃了 羊肉 的 7号
17392生产了包子 的 8号
22716生产了猪肉 的 8号
23616 吃了 羊肉 的 8号
7580生产了羊肉 的 9号
13116 吃了 包子 的 7号
17392生产了包子 的 9号22716生产了猪肉 的 9号
23616 吃了 猪肉 的 7号
13116 吃了 包子 的 8号
23616 吃了 猪肉 的 8号
13116 吃了 羊肉 的 9号
13116 吃了 猪肉 的 9号
23616 吃了 包子 的 9号
主进程
Process finished with exit code 0
四、进程
进程是一个执行中的程序,资源分配的最小单位。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。在单核CPU系统中的多进程,内存中可以有许多程序,但在给定一个时刻只有一个程序在运行;就是说,可能这一秒在运行进程A,下一秒在运行进程B,虽然两者都在内存中,都没有真正同时运行。
进程是一个实体,都会有自己的地址空间,里面有文本区域,数据区域,堆栈。
文本区域:存储cpu执行的代码
数据区域:执行一些存储变量,动态分配的内存
堆栈:存储在活动过程中调用的指令和变量这些
进程具有动态性:会动态产生和动态消亡
并发性
独立性
异步性:有些进程是相互制约的,而且它会有间歇性,堵塞呀之类的
实例
import time,os,random
import multiprocessing
def test1(a):
print("test1 start",a)
print("test1的进程id为:",os.getpid())#查看当前进程id
print("test1的父进程id为:",os.getppid())#查看当前父进程id
time.sleep(1)
def test2(a):
print("test2 start",a)
print("test2的进程id为:",os.getpid())#查看当前进程id
print("test2的父进程:",os.getppid())#查看当前父进程id
time.sleep(1)
def main():
print("main函数的进程id为:",os.getpid())
#创建进程
t1 = multiprocessing.Process(target=test1,args=("hello",))
t2 = multiprocessing.Process(target=test2,args=("world",))
#启动进程
t1.start()
t2.start()
print("haha")
pass
if __name__=='__main__':
main()
运行结果为:
main函数的进程id为: 22664
haha
test1 start hello
test1的进程id为: 24924
test2 start world
test2的进程id为: 18556
test1的父进程id为: 22664
test2的父进程: 22664
Process finished with exit code 0
五、并发系列process学习
进程调度:
1、先来先服务算法:利用长作业的进程,适合cpu繁忙的作业,而不是io繁忙的作业
2、短作业优先调度算法:不能保证紧急的作业被完成
3、时间片轮转:将cpu的处理时间分成固定大小的时间片,分为几百毫秒,几十毫秒这种。。。。
调度分配一些可以抢占的资源,可以分配和收回
程序的状态:
就绪状态,执行/运行状态,阻塞状态
process进程是一个资源分配的总和,线程是拿资源去执行
多进程多任务是多个资源每个资源至少一个人做事
多线程多任务是一个资源多个人做事
实例一
import time,os,random
from multiprocessing import Process
def p(name):
print("hello",name)
print("子进程")
time.sleep(1)
def main():
p1 = Process(target=p,args=("xiaoming",))
p1.start()
print("主进程")
pass
if __name__=='__main__':
main()
运行结果为:
主进程
hello xiaoming
子进程
Process finished with exit code 0
如果需要把上述↑的实例中,子进程做五次呢?
实例二
import time,os,random
from multiprocessing import Process
def p(name):
print("hello",name)
print("子进程")
time.sleep(1)
def main():
p_list = []
for i in range(5):
p1 = Process(target=p,args=("小明",))
p1.start()
p_list.append(p1)
print(p_list)
print("主进程")
pass
if __name__=='__main__':
main()
运行结果为:
主进程
hello 小明
子进程
hello 小明
子进程
hello 小明
子进程
hello 小明
子进程
hello 小明
子进程
Process finished with exit code 0
那再如果想让一个事情先做,然后间隙中又去做另一个事呢?,而且他们都是子进程,该怎么办呢?
实例三
import time,os,random
from multiprocessing import Process
def test1():
print("test1 start")
time.sleep(5)
print("test1 stop")
def test2():
print("test2 start")
time.sleep(2)
print("test2 stop")
def main():
print("main start")
t1 = Process(target=test1)
t2 = Process(target=test2)
t1.start()
t2.start()
print("main stop")
pass
if __name__=='__main__':
main()
运行结果为:
main start
main stop
test1 start
test2 start
test2 stop
test1 stop
Process finished with exit code 0
join:阻塞当前进程,直到调用join的方法的进程执行完,再继续执行当前进程
实例四
import time,os,random
from multiprocessing import Process
def test1():
print("test1 start")
time.sleep(5)
print("test1 stop")
def test2():
print("test2 start")
time.sleep(2)
print("test2 stop")
def main():
print("main start")
t1 = Process(target=test1)
t2 = Process(target=test2)
t1.start()
t2.start()
t1.join()
print("main stop")
pass
if __name__=='__main__':
main()
结果运行为:
main start
test1 start
test2 start
test2 stop
test1 stop
main stop
Process finished with exit code 0
六、守护进程
守护进程就是Daemon程序,是一种在系统后台执行的程序,它独立于控制终端并且执行一些周期任务或触发事件,通常被命名为"d"字母结尾,如常见的httpd、syslogd、systemd和dockerd等。
实例
守护进程一定要在start之前开启,设置True就是守护进程开始(但是p2没有开守护进程可以一直执行下去)
在父进程代码结束之后,守护进程立马停止运行
import time,os,random
from multiprocessing import Process
def test1():
print("test1 start")
time.sleep(1)
print("test1 stop")
def test2():
print("test2 start")
time.sleep(5)
print("test2 stop")
def main():
print("main start")
p1 = Process(target=test1)
p2 = Process(target=test2)
p1.daemon = True #开启守护进程
p1.start()
p2.start()
time.sleep(0.1)
print("main stop")
pass
if __name__=='__main__':
main()
运行结果为:
没有test1 stop,因为父进程结束了
main start
test1 start
test2 start
main stop
test2 stop
Process finished with exit code 0