from multiprocessing import Process import time # 妃子的一生 def task(): print("入宫了.....") time.sleep(50) print("妃子病逝了......") if __name__ == '__main__': # 康熙登基了 print("登基了.....") # 找了一个妃子 p = Process(target=task) # 设置为守护进程 必须在开启前就设置好 p.daemon = True #设定好守护进程的标志 p.start() # 康熙驾崩了 time.sleep(3) print("故事结束了!") 当父进程关闭以后,守护进程不管有没有走完下面的代码并不会接着往下走,随着结束掉
def task1(): #使用就上锁,不要对同一把索使用多次acquire,使用一次对应一次release # lock.acquire() print('我好帅') time.sleep(random.randint(0,3)) print('阿花真美') # lock.release() def task2(): # lock.acquire() print('我好帅') time.sleep(random.randint(0, 3)) print('阿芳真美') # lock.release() # # # # if __name__ == '__main__': # lock = Lock() p1 = Process(target=task1)
打印结果
D:python36python.exe "D:/代码文件夹/day 35/开发安全.py"
我好帅
我好帅
阿芳真美
阿花真美
可以看出多进程在同时运行的时候出现了抢占cpu的情况,使得打印结果,并不是我们所想要的,这时候只要一把互斥锁就可以解决这个问题了。
def task1(lock): #使用就上锁,不要对同一把索使用多次acquire,使用一次对应一次release lock.acquire() #上锁 print('我好帅') time.sleep(random.randint(0,3)) print('阿花真美') lock.release() #解锁 def task2(lock): lock.acquire() #上锁 print('我好帅') time.sleep(random.randint(0, 3)) print('阿芳真美') lock.release() #解锁 # # # # if __name__ == '__main__': lock = Lock() #让进程使用同一把互斥锁 p1 = Process(target=task1,args=(lock,)) p2 = Process(target=task2,args=(lock,)) # # p1.start() p2.start()
互斥锁并不是真的把资源给锁了起来,只是当有一个进程先站住之后,在代码层面进行限制,在该进程没有结束操作之前不让其他进程进行操作。
在程度上来说join函数,也可以解决并行数据错乱的问题,只是他与互斥锁最大的区别是:join 是完全将并发任务变成了串行,这样虽然解决了数据错乱的
问题,但是原本的并发的高效率,也被随之丢弃,进程的执行顺序会被固定,父进程在子进程没有结束的情况下只能等着。而互斥锁则是会保证原有进程同时并发,父进程可以去执行其他任务,锁任意位置的代码,锁一行都可以。
ipc是指进程间的通讯,进程之间的内存是相互隔离的,大概一个进程的数据想要传给另外一个进程时,大范围上有以下几种方式:管道,文件,socket,和共享内存。
管道只能实现单方面通讯,数据还都是二进制。
文件实在硬盘上创建共享文件,优点是几乎不受数据大小的影响,缺点是速度慢。
socket对编程的复杂度较高。
共享内存必须由操作系统来分配,优点是传输速度快,缺点就是数据量不能太大。
from multiprocessing import Process,Manager,Lock import time def task(data,l): l.acquire() num = data["num"] # time.sleep(0.1) data["num"] = num - 1 l.release() if __name__ == '__main__': # 让Manager开启一个共享的字典 m = Manager() data = m.dict({"num":10}) l = Lock() for i in range(10): p = Process(target=task,args=(data,l)) p.start() time.sleep(2) 这里必须有一个睡眠操作,所有的子进程在处理数据需要时间,这时候如果没有时间间隔的话,直接打印就会出错,所以要有一个时间间隔
等数据都处理完之后在进行打印 print(data)
需要注意的是Manager创建的一些数据结构是不带互斥锁的,所以可能会出现一些问题。
from multiprocessing import Queue # 创建队列 不指定maxsize 则没有数量限制 q = Queue(3) # 存储元素 # q.put("abc") # q.put("hhh") # q.put("kkk") # print(q.get()) # q.put("ooo") # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行 #取出元素 # print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续 # print(q.get()) # print(q.get())
还有一些常用的方法
#block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列为空时 抛出异常 q.get(block=True,timeout=2) # block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列满了时 抛出异常 # q.put("123",block=False,) # timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效
解决方案:将两者直接分开,各自去完成自己需要完成的任务,为了能实现数据之间的交互,在两者之间创建一个共享内存,生产者将完成后的数据存储
到共享内存中,消费者则在需要数据的时候去共享内存中取出来就可以了。这样两边就可以互不影响。
def eat(q): for i in range(10): # 要消费 rose = q.get() time.sleep(random.randint(0, 2)) print(rose,"吃完了!") # 生产任务 def make_rose(q): for i in range(10): # 再生产 time.sleep(random.randint(0, 2)) print("第%s盘青椒肉丝制作完成!" % i) rose = "第%s盘青椒肉丝" % i # 将生成完成的数据放入队列中 q.put(rose) if __name__ == '__main__': # 创建一个共享队列 q = Queue() make_p = Process(target=make_rose,args=(q,)) eat_p = Process(target=eat,args=(q,)) make_p.start() eat_p.start()