目录
正常:进程代码运行结束之后并没有直接结束而是需要等待回收子进程资源才能结束; 僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。. 如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源; 通俗理解:如果我们出去露营,在回家的时候是不是需要把摆出来的行李收拾回去才可以呀,不能人嗨了东西不要了;
from multiprocessing import Process
import time
def process_test(name):
print(f'{name} is running!')
time.sleep(2)
print(f'{name} is over!')
if __name__ == '__main__':
p = Process(target=process_test,args=('Hammer',))
p.start()
print('主线程')
# 主进程执行了print输出语句已经没有代码可以执行了,但是子进程是在该进程内开设的,需要等待回收子进程的资源
即主进程已经死亡(非正常)但是子进程还在运行 孤儿进程 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。 孤儿进程将被init进程 (进程号为1)所收养,并由init进程对它们完成状态收集工作; 通俗的理解:“没爹没妈”
这样是浪费资源的,没有主进程回收子进程,最后会由操作系统linit回收;
守护进程:即守护着某个进程 一旦这个进程结束那么也随之结束; 通俗理解:“进程陪葬”
from multiprocessing import Process
import time
def test(name):
print('总管:%s is running' % name)
time.sleep(3)
print('总管:%s is over' % name)
if __name__ == '__main__':
p = Process(target=test, args=('Hammer',))
p.daemon = True # 设置为守护进程(一定要放在start语句上方)
p.start()
print("皇帝寿终正寝")
# 只有主进程的print语句,而子进程的输出语句不会执行
# 当主进程结束了,子进程也随即结束,就相当于皇帝死了,太监们就别玩了,而是去陪葬
注意:p.daemon = True在启动子进程前运行!
问题:并发情况下操作同一份数据 极其容易造成数据错乱 解决措施:将并发变成串行 虽然降低了效率但是提升了数据的安全 锁(行锁、表锁···)就可以实现将并发变成串行的效果
'''data.txt'''
{"ticket_num":1}
'''buy.py'''
import json
from multiprocessing import Process, Lock
import time
import random
# 查票
def search(name):
with open(r'data.txt', 'r', encoding='utf8') as f:
data_dict = json.load(f) # 反序列化
ticket_num = data_dict.get('ticket_num')
print('%s查询余票:%s' % (name, ticket_num))
# 买票
def buy(name):
# 先查票
with open(r'data.txt', 'r', encoding='utf8') as f:
data_dict = json.load(f)
ticket_num = data_dict.get('ticket_num')
# 模拟一个延迟
time.sleep(random.random())
# 判断是否有票
if ticket_num > 0:
# 将余票减一
data_dict['ticket_num'] -= 1
# 重新写入数据库
with open(r'data.txt', 'w', encoding='utf8') as f:
json.dump(data_dict, f)
print('%s: 购买成功' % name)
else:
print('不好意思 没有票了!!!')
def run(name,mutex):
search(name)
mutex.acquire() # 抢锁
buy(name)
mutex.release() # 释放锁
# 只需将买票上锁
# 开设多个进程
if __name__ == '__main__':
mutex = Lock() # 多进程如果不上锁就会出现数据错乱
for i in range(1, 11):
p = Process(target=run, args=('用户%s' % i,mutex))
p.start()
# 抢锁的概念就相当于十个人去抢一个茅坑,一个人拉上了,后面的人只能等着了,拉完了(释放锁),别人才能继续抢锁;
# 在以后的编程生涯中 几乎不会解除到自己操作锁的情况
参考:https://blog.csdn.net/qq_34337272/article/details/81072874
队列:先进先出 方法示例写在代码中
from multiprocessing import Queue
# 括号内可以填写最大的等待数,队列最多装5个数
q = Queue(5)
# put方法,存放数据
q.put(111)
q.put(222)
print(q.full()) # 判断队列是否放满
q.put(333)
q.put(444)
q.put(555)
print(q.full()) # 队列放满了
# 超出范围原地等待,直到有空缺位置
# q.put(666)
# 提取数据
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# 只有五个数,取六个的时候,原地等待,直到有数据过来
# print(q.get())
# 判断数据是否为空
print(q.empty())
# 获取数据,没有数据立刻报错
print(q.get_nowait()) # queue.Empty
注意:
full
和get_nowait
不能用于多进程情况下的精确使用,如果另外进程从当前进程拿数据,或者存入数据,会造成数据的偏差,从而full方法
和get_nowait方法
判断就会出错;
队列的使用就可以打破进程间默认无法通信的情况,IPC机制来实现
# 主进程和子进程通过消息队列来实现数据互通
# IPC机制来解决进程间无法通信的问题
from multiprocessing import Queue,Process
def consumer(q):
print(q.get()) # 子进程获取主进程存放的数据
q.put("子进程存放的数据") # 模拟开设的子进程中存放的数据
if __name__ == '__main__':
q = Queue() # 生成队列
q.put("主进程存放的数据") # 模拟数据
# 开设子进程
p = Process(target=consumer,args=(q,))
p.start()
p.join() # 用join方法来确认子进程执行完,主进程再去取数据
print(q.get()) # 主进程获取
print("主进程")
# 子进程和子进程通过消息队列来实现数据互通
from multiprocessing import Queue,Process
def process1(q):
q.put("子进程1存放的数据!")
def process2(q):
print(f'子进程2取子进程1存放的数据:>>>{q.get()}')
if __name__ == '__main__':
q = Queue()
p1 = Process(target=process1,args=(q,))
p2 = Process(target=process2,args=(q,))
p1.start()
p2.start()
👉[23种设计模型参考博文]((3条消息) Python之23种设计模式_Burgess_zheng的博客-CSDN博客_python 设计模式)
爬虫领域用的比较多,该模型需要解决供需不平衡的现象
# 使用到模块JoinableQueue,能够监测谁给队列中放数据和取数据
from multiprocessing import Queue, Process, JoinableQueue
import time
import random
def producer(name, food, q):
for i in range(10):
print('%s 生产了 %s' % (name, food))
q.put(food)
time.sleep(random.random())
def consumer(name, q):
while True:
data = q.get()
print('%s 吃了 %s' % (name, data))
q.task_done()
if __name__ == '__main__':
# q = Queue()
q = JoinableQueue() # 队列模块换一下
p1 = Process(target=producer, args=('厨子Hammer', '玛莎拉', q))
p2 = Process(target=producer, args=('印度阿三', '飞饼', q))
p3 = Process(target=producer, args=('泰国阿人', '榴莲', q))
c1 = Process(target=consumer, args=('班长阿飞', q))
p1.start()
p2.start()
p3.start()
c1.daemon = True # 守护进程
c1.start()
p1.join()
p2.join()
p3.join()
q.join() # 等待队列中所有的数据被取干净
print('主进程')
# 使用模块JoinableQueue并且添加守护进程和join方法是为了让消费者结束等待的情况