互斥锁
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,
竞争带来的结果就是错乱,如何控制,就是加锁处理
part1:多个进程共享同一打印终端
#并发运行,效率高,但竞争同一打印终端,带来了打印错乱 from multiprocessing import Process,Lock import os,time,random def task(mutex): print("111111") time.sleep(2) print("222222") time.sleep(2) print("333333") if __name__ == "__main__": mutex = Lock() p1 = Process(target=task,args=(mutex,)) p2 = Process(target=task,args=(mutex,)) p3 = Process(target=task,args=(mutex,)) p1.start() p2.start() p3.start() #运行结果 #111111 #111111 #111111 #222222 #222222 #222222 #333333 #333333 #333333
加锁后由并发变成了串行
from multiprocessing import Process,Lock import os,time,random def task(mutex): mutex.acquire() print("111111") time.sleep(2) print("222222") time.sleep(2) print("333333") mutex.release() if __name__ == "__main__": mutex = Lock() p1 = Process(target=task,args=(mutex,)) p2 = Process(target=task,args=(mutex,)) p3 = Process(target=task,args=(mutex,)) p1.start() p2.start() p3.start() #运行结果 #111111 #222222 #333333 #111111 #222222 #333333 #111111 #222222 #333333
互斥锁与join的区别
join是等一个进程运行完后下一个进程才运行,而互斥锁是进程都执行了,不过这个任务每次都只能有一个进程执行,谁抢到谁运行。
且join是全局的,一个进程没完不会开启下一个进程,互斥锁可以局部进行,专门为某一个任务加锁。
#有一个名为db.txt的文件,内容为{"count": 1} def search(): #查票 with open('db.txt',encoding='utf-8') as f: dic=json.load(f) print('%s 剩余票数 %s' %(os.getpid(),dic['count'])) def get(): #买票 with open('db.txt',encoding='utf-8') as read_f: dic=json.load(read_f) if dic['count'] > 0: dic['count']-=1 time.sleep(random.randint(1,3)) #模拟手速+网速 with open('db.txt','w',encoding='utf-8') as write_f: json.dump(dic,write_f) print('%s 抢票成功' %os.getpid()) def task(): search() get() if __name__ == '__main__': for i in range(20): #模拟20人买票 p=Process(target=task) p.start() p.join() #运行结果-使用join其他人不能够查票 8596 剩余票数 1 8596 抢票成功 4092 剩余票数 0 9088 剩余票数 0 7508 剩余票数 0 10424 剩余票数 0 3216 剩余票数 0 15432 剩余票数 0 6136 剩余票数 0 5440 剩余票数 0 7744 剩余票数 0 14744 剩余票数 0 14768 剩余票数 0 15812 剩余票数 0 7140 剩余票数 0 10076 剩余票数 0 15364 剩余票数 0 8332 剩余票数 0 16180 剩余票数 0 3052 剩余票数 0 8592 剩余票数 0
使用锁的方式
def search(): with open('db.txt',encoding='utf-8') as f: dic=json.load(f) print('%s 剩余票数 %s' %(os.getpid(),dic['count'])) def get(): with open('db.txt',encoding='utf-8') as read_f: dic=json.load(read_f) if dic['count'] > 0: dic['count']-=1 time.sleep(random.randint(1,3)) #模拟手速+网速 with open('db.txt','w',encoding='utf-8') as write_f: json.dump(dic,write_f) print('%s 抢票成功' %os.getpid()) def task(mutex): search() mutex.acquire() get() # 只为买票加锁 mutex.release() if __name__ == '__main__': mutex=Lock() for i in range(20): p=Process(target=task,args=(mutex,)) p.start() #结果-并不影响查票,但买票只能一个一个买 10356 剩余票数 1 15436 剩余票数 1 10008 剩余票数 1 14496 剩余票数 1 5668 剩余票数 1 15884 剩余票数 1 7288 剩余票数 1 7308 剩余票数 1 15740 剩余票数 1 152 剩余票数 1 12260 剩余票数 1 14988 剩余票数 1 15396 剩余票数 1 15696 剩余票数 1 1036 剩余票数 1 7632 剩余票数 1 15392 剩余票数 1 14600 剩余票数 1 12408 剩余票数 1 16168 剩余票数 1 10356 抢票成功
线程互斥锁
线程之间数据共享,如果多个线程同时修改数据,会产生意外的结果
from threading import Thread,Lock import time n=100 def task(): global n temp=n time.sleep(0.1) #模仿处理时间 n=temp-1 if __name__ == '__main__': # mutex=Lock() t_l=[] for i in range(100): t=Thread(target=task) t_l.append(t) t.start() for t in t_l: t.join() print(n) # 运行结果-他们几乎是同时拿到了数据,进行处理,但拿到的是相同的数据 99
加锁
from threading import Thread,Lock import time n=100 def task(): #可以不传递mutex,线程共享资源,而进程必须要传过去 global n mutex.acquire() temp=n time.sleep(0.1) n=temp-1 mutex.release() #另外一种写法
# global n
# with mutex:
# temp=n
# time.sleep(0.1)
# n=temp-1
if __name__ == '__main__': mutex=Lock() t_l=[] for i in range(100): t=Thread(target=task) t_l.append(t) t.start() for t in t_l: t.join() print(n) #执行结果-进行加锁,使他们不能同时拿到数据,只有在一个进程结束之后才可以拿 #0
死锁与递归锁
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程