进程隔离是为了保护操作系统中进程互不干扰而设计的一组不同硬件和软件的技术
这个技术是为了避免进程A写入进程B的情况发生。进程的隔离实现,使用了虚拟地址空间。进程A的虚拟地址和进程B的进程隔离的安全性通过禁止进程间内存的访问可以方便实现
from multiprocessing import Process
n = 100
def work():
global n
n = 0
print('子进程内:‘,n)
if __name__ == '__main__':
p = Process(target=work)
p.start()
print('主进程内:',n)
守护进程
会随着主进程的结束而结束,通俗点的说类似于古代的君王和服侍君王的太监,妃子等一干人,只要君王死了其他人都得陪葬。
主进程创建守护进程
其一:守护进程会在主进程代码执行结束后终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError:daemonic process are not allowed to have children
注意:进程之间是相互独立的,主进程代码运行结束,守护进程随即终止
impo‘)rt os
import time
from multiprocessing import Process
class Myprocess(Process):
def __init__(self,person):
super().__init__()
self.person = person
def run(self):
print(os.getpid(),self.name)
print('%s正在聊天‘%self.person)
p = Myprocess('敏’)
p.daemon=True # 一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
p.start()
time.sleep(10). # 在sleep时查看进程id对应的进程ps-eflgrep id
print('主‘)
**
**
from multiprocessing import Process
def foo():
print(123)
time.sleep(1)
print('end123')
def bar():
print(123)
time.sleep(3)
print('end456')
p1 = Process(target=foo)
p1.start()
p2.start()
time.sleep(0.1)
print("main--------"). # 打印该行则主进程代码结束,则守护进程p1应该被终止。可能会有p1任务执行的打印信息123,因为主进程打印main---时,p1也执行,但是随即被终止了
进程同步(multiprocessing.Lock)
锁——(multiprocess.Lock)
进程之间数据不共享,但是共享一套文件,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理。
多进程模拟抢票实例
#文件db的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
from multiprocessing import Process,Lock
import time,json,random
def search():
dic=json.load(open('db'))
print('\033[43m剩余票数%s\033[0m' %dic['count'])
def get():
dic=json.load(open('db'))
time.sleep(0.1) #模拟读数据的网络延迟
if dic['count'] >0:
dic['count']-=1
time.sleep(0.2) #模拟写数据的网络延迟
json.dump(dic,open('db','w'))
print('\033[43m购票成功\033[0m')
def task():
search()
get()
if __name__ == '__main__':
for i in range(100): #模拟并发100个客户端抢票
p=Process(target=task)
p.start()
# 引发问题:数据写入错乱
互斥锁保证数据安全
from multiprocessing import Process,Lock
import time,json,random
def search():
dic=json.load(open('db'))
print('\033[43m剩余票数%s\033[0m' %dic['count'])
def get():
dic=json.load(open('db'))
time.sleep(random.random()) # 模拟读数据的网络延迟
if dic['count'] >0:
dic['count']-=1
time.sleep(random.random()) # 模拟写数据的网络延迟
json.dump(dic,open('db','w'))
print('\033[32m购票成功\033[0m')
else:
print('\033[31m购票失败\033[0m')
def task(lock):
search()
lock.acquire() # 将买票这一环节由并发变成了串行,牺牲了运行效率但是保证了数据的安全
get()
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(100): # 模拟并发100个客户端抢票
p=Process(target=task,args=(lock,))
p.start()
总结:加锁可以保证多个进程修改同一块数据,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度时慢了,但牺牲了速度却保证了数据安全。
问题:虽然可以用文件共享数据显示进程数据通信但问题是:
效率低(共享数据基于文件,而文件是硬盘上的数据)
需要自己加锁处理
我们知道进程之间数据是相互隔离的,要想实现进程间的通信(IPC机制),就必须借助于一些技术才可以,比如multiprocess模块中的:队列和管道,这两种方式都是可以实现进程间数据传输的,由于队列是管道+锁的方式实现,所以我们着重研究队列即可
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现进程之间的数据传递
总结:队列支持多个人从队列的一端放入数据,同样支持多个人从队列的另一端取数据
Queue([maxsize]) # 创建共享的进程队列 队列底层使用管道和锁定实现。
# 参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
from multiprocessing import Queue
q=Queue(3) # 创建一个最大只能容纳3个数据的队列
"""
常用方法
put ,get ,put_nowait,get_nowait,full,empty
"""
q.put(3) # 往队列中存放数据
q.put(3)
q.put(3)
q.put(3) # 如果队列已经满了,程序就会停在这里,等待数据被别人取走,再将数据放入队列。如果队列中的数据一直不被取走,程序就会永远停在这里。
try:
q.put_nowait(3) # 可以使用put_nowait,如果队列满了不会阻塞,但是会因为队列满了而报错。
except: # 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去,但是会丢掉这个消息。
print('队列已经满了')
# 因此,我们再放入数据之前,可以先看一下队列的状态,如果已经满了,就不继续put了。
print(q.full()) # 判断队列中数据是否已存放满了
print(q.get()) # 从队列中获取数据
print(q.get())
print(q.get())
print(q.get()) # 同put方法一样,如果队列已经空了,那么继续取就会出现阻塞。
try:
q.get_nowait(3) # 可以使用get_nowait,如果队列满了不会阻塞,但是会因为没取到值而报错。
except: # 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去。
print('队列已经空了')
print(q.empty()) # 判断队列中数据是否已经被全部取出
import time
from multiprocessing import Process, Queue
def f(q):
q.put('hello') #调用主函数中p进程传递过来的进程参数 put函数为向队列中添加一条数据。
if __name__ == '__main__':
q = Queue() # 创建一个Queue对象
p = Process(target=f, args=(q,)) #创建一个进程
p.start()
print(q.get()) # 从队列中获取数据
p.join()
from multiprocessing import Queue,Process
def producer(q):
q.put('hello big baby!')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p = Process(target=producer,args=(q,))
p.start()
p1 = Process(target=consumer,args=(q,))
p1.start()