一、join让主进程等待子进程结束后再结束,并回收子进程资源,主进程结束并回收资源python
二、未使用join,而且主进程 “ 正常结束 ” ,子进程与主进程一并被回收资源json
一、僵尸进程安全
在子进程结束后,主进程没有正常结束,子进程PID不会被回收网络
缺点:操做系统中的PID号是有限的,若有子进程PID 号,没法正常回收,则会占用PID号,浪费资源,若PID号满了,则没法建立新的进程并发
二、孤儿进程dom
在子进程没有结束时,主进程没有 “ 正常结束” ,子进程PID不会被回收优化
操做系统有优化进制(孤儿院):ui
当主进程意外终止,操做系统会检测是否有正在运行的子进程,会把他们放到孤儿院中,让操做系统帮忙回收操作系统
当主进程结束时,子进程也必须结束,并回收code
在不使用join的状况下,使用obj.daemon = True,设置在obj.start()以前,让主进程结束,子进程也跟着结束,并回收
from multiprocessing import Process import time def data(): print('子进程start') time.sleep(10) print('子进程end') if __name__ == '__main__': obj = Process(target=data) # 守护进程必须在obj.start()以前设置 obj.daemon = True obj.start() time.sleep(1) print('主进程结束') 》》》 # 子进程start # 主进程结束
因为建立进程是开辟新的内存空间,因此进程之间的数据是相互隔离的
# 进程之间的数据是隔离的 from multiprocessing import Process num = 100 def data1(num): num += 1 # 此处打印的是子进程data1的num,子进程与主进程数据是隔离的 print(num) # 11 def data2(): global num num += 10 # 此处打印的是子进程data2的num,子进程与主进程数据是隔离的 print(num) # 110 if __name__ == '__main__': obj1 = Process(target=data1, args=(10,)) obj2 = Process(target=data2) obj1.start() obj2.start() obj2.join() obj1.join() # 此处打印的是主进程的num,子进程与主进程数据是隔离的 print(num) # 100 print(num) # 100
互斥锁是用来保证数据读写安全的,在修改同一个数据时,同一时间只能有一个任务能够进行修改,即串行的修改,保证数据安全
# json_data文件中{"num": 0} ,json数据里面必须是双引号 from multiprocessing import Process from multiprocessing import Lock import json import time import random lock = Lock() # 查票 def search(name): with open('json_data.json', 'r', encoding= 'utf-8') as f: data_dic = json.load(f) print(f'用户{name}查看余票,余票{data_dic.get("num")}') # 买票 def buy(name): # 网络延时 with open('json_data.json', 'r', encoding= 'utf-8') as f: data_dic = json.load(f) if data_dic.get('num') > 0: data_dic['num'] -= 1 time.sleep(random.random()) with open('json_data.json', 'w', encoding= 'utf-8') as f: json.dump(data_dic,f) print(f'用户{name}抢票成功') else: print(f'用户{name}抢票失败') def run(name,lock): search(name) # 加锁 lock.acquire() buy(name) # 释放锁 lock.release() if __name__ == '__main__': # 开启多进程,实现并发 for i in range(10): obj = Process(target=run, args=(f'jason{i},',lock)) obj.start()
队列(FIFO):先进先出:先存放的数据,就先取出来
堆栈(FILO):先进后出
至关于第三方的管道,能够存放数据
应用 :让进程之间的数据能够交互
有三种调用方式:
使用Queue(5)指的是队列中只能存放5份数据,默认长度是32,生成一个对象经过obj.put( x )往队列中放数据,或者使用obj.put_nowait( x )往队列中存放数据,使用obj.get()或obj.get_nowait()来获取队列中的数据
put :只要队列满了,就会进入阻塞
put_nowait :队列满了,就会报错
get:只要队列中有数据,就能获取数据,若没有则会进入阻塞
get_nowait : 只要队列中有数据,就能获取数据,若没有则会报错
from multiprocessing import Queue # multiprocessing提供队列 先进先出 from multiprocessing import JoinableQueue # 基于 Queue 封装的队列 先进先出 import queue # python内置的队列 先进先出 Queue(5)指的是队列中只能存放5份数据,默认长度是32
# 第一种: # 生成队列对象 obj = Queue(5) # 第二种: # 生成队列对象 obj = JoinableQueue(5) # 第三种: # 生成队列对象 obj = queen.Queue(5) # 添加数据到队列中 obj.put('1') print('添加一个数1') obj.put('2') print('添加一个数2') obj.put('3') print('添加一个数3') obj.put('4') print('添加一个数4') obj.put('5') print('添加一个数5') # put :只要队列满了,就会进入阻塞 # obj.put('6') # print('添加一个数6') # put_nowait :队列满了,就会报错 # obj.put_nowait('6') # print('添加一个数6') print(obj.get()) print(obj.get()) print(obj.get()) print(obj.get()) print(obj.get()) # get:只要队列中有数据,就能获取数据,若没有则会进入阻塞 # print(obj.get()) # get_nowait : 只要队列中有数据,就能获取数据,若没有则会报错 # print(obj.get_nowait())
IPC机制:是进程之间实现通讯,使用队列让两个进程之间的数据进行交互,实现进制之间的通讯
from multiprocessing import Process from multiprocessing import JoinableQueue import time def task1(q): x = 100 q.put(x) print(f'添加数据{x}到队列中') time.sleep(2) # 获取队列中的数据 # task2中又放了数据到队列中被获取到 print(q.get()) # 200 def task2(q): # 获取队列中的数据,task1中先放了数据先获取到task1中的数据 res = q.get() print(f'获取的数据{res}') # 获取的数据100 # 放数据到队列中 q.put(200) if __name__ == '__main__': q = JoinableQueue(5) # 先放task1数据 p1 = Process(target=task1, args=(q,)) # 再放task2数据 p2 = Process(target=task2, args=(q,)) p1.start() p2.start()
生产者:生产数据的
消费者:使用数据的
有两种状况,一、生产者生产的大于消费者所需的,供大于求;二、生产者生产的不够消费者使用的,供不该求
生产者:往队列中加数据
消费者:从队列中取数据
from multiprocessing import JoinableQueue from multiprocessing import Process import time # 生产者:生产数据——》队列 def producer(name, food, q): msg = f'{name}生产了{food}' # 往队列中加数据 q.put(food) print(msg) # 消费者: 从队列中使用数据 def customer(name, q): while True: try: time.sleep(1) # 从队列中取数据 food = q.get() msg = f'{name}消费了{food}' print(msg) except Exception: break if __name__ == '__main__': # 默认长度32 q = JoinableQueue() # 建立生产者 for i in range(10): p1 = Process(target=producer, args=('tank', f'油条{i}', q)) p1.start() # 建立两个消费者 c1 = Process(target=customer, args=('Mr沈', q)) c2 = Process(target=customer, args=('shen', q)) c1.start() c2.start()