我们之前做了多进程并发,那么你们有没有发现问题。如果说多个进程共享同一个数据,比如抢火车票大家同时在客户端查看同时购买会出现什么问题呢?今天我们将讲述进程锁还有进程间通信,进程之间彼此隔离,他们需要一个第三方联系起来。
一、互斥锁
进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理
注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改,没错,速度是慢了,牺牲了速度而保证了数据安全。
1、上厕所
先举个通俗易懂的例子,家里的厕所,你要上厕所进去后会先锁门,厕所门就相当于一个互斥锁,当你在里面的时候别人过来上厕所就只能在门口等。
from multiprocessing import Process,Lock
import os
import time
def work(mutex):
mutex.acquire() #上锁
print('task[%s] 上厕所' %os.getpid())
time.sleep(3)
print('task[%s] 上完厕所' %os.getpid())
mutex.release() #开锁
if __name__ == '__main__':
mutex=Lock() #实例化(互斥锁)
p1=Process(target=work,args=(mutex,))
p2=Process(target=work,args=(mutex,))
p3=Process(target=work,args=(mutex,))
p1.start()
p2.start()
p3.start()
print('start...')
2、模拟抢票
#文件db的内容为:{"count":1} #票数可以自己定义
#注意一定要用双引号,不然json无法识别
from multiprocessing import Process,Lock
import json
import time
import random
import os
def search() : #查看票数
dic=json.load(open('db.txt',))
print('剩余票数%s' %dic['count'])
def get_ticket() : #购票
dic = json.load(open('db.txt',))
if dic['count'] > 0 :
dic['count'] -= 1
json.dump(dic,open('db.txt','w'))
print('%s 购票成功' %os.getpid())
def task(mutex) : #购票流程
search()
time.sleep(random.randint(1, 3)) #模拟购票一系列繁琐的过程所花费的时间
mutex.acquire()
get_ticket()
mutex.release()
if __name__ == '__main__' :
mutex = Lock()
for i in range(50):
p = Process(target=task,args=(mutex,))
p.start()
二、Process对象其他属性使用案例补充
1、deamon守护进程
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
ps:
from multiprocessing import Process
import os
import time
def work():
print('%s is working' %os.getpid())
time.sleep(10)
print('%s is ending' % os.getpid())
if __name__ == '__main__':
p1=Process(target=work)
p2=Process(target=work)
p3=Process(target=work)
p1.daemon=True
p2.daemon=True
p3.daemon=True
p1.start()
p2.start()
p3.start()
time.sleep(2)
print('start。。。')
2、join等待子进程
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
ps:
from multiprocessing import Process
import os
import time
def work():
print('%s is working' %os.getpid())
time.sleep(3)
if __name__ == '__main__':
p1=Process(target=work)
p2=Process(target=work)
p3=Process(target=work)
p1.daemon=True
p2.daemon=True
p3.daemon=True
p1.start() #初始化1
p2.start() #初始化2
p3.start() #初始化3
p3.join()
p1.join()
p2.join()
print('基于初始化的结果来继续运行')
3、terminate,is_alive,name,pid
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.name:进程的名称
p.pid:进程的pid
ps:
from multiprocessing import Process
import os
import time
def work():
print('%s is working' %os.getpid())
time.sleep(3)
if __name__ == '__main__':
p1=Process(target=work)
p2=Process(target=work)
p3=Process(target=work)
p1.start() #初始化1
p2.start() #初始化2
p3.start() #初始化3
p1.terminate() #不建议使用
print(p1.is_alive())
#虽然已经强制终止进程了但是操作系统终止进程也需要时间所以此时还是True
print(p1.name) #如果没有起名默认Process-1后面的数字按子进程顺序排
print(p2.name)
print(p1.pid) # p1.pid == os.getpid()
print('基于初始化的结果来继续运行')
三、进程间通信