-互斥锁
对于模拟多人查票抢票
票数放在文件中db.txt
{"count":1}
程序
from multiprocessing import Process
import json
import time
import random
import os
def search():
time.sleep(random.randint(1,3))
dic=json.load(open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','r',encoding='utf-8'))
print('%s 查看剩余票数 %s' %(os.getpid(),dic['count']))
def get():
dic=json.load(open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','r',encoding='utf-8'))
if dic['count']>0:
dic['count']-=1
time.sleep(random.randint(1,3))
json.dump(dic,open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','w',encoding='utf-8')) #将买完票写回
print('%s 购票成功' %os.getpid() )
def task():
search()
get()
if __name__=='__main__':
for i in range(10):
p=Process(target=task)
p.start()
运行结果:错误
8640 查看剩余票数 1
14440 查看剩余票数 1
15580 查看剩余票数 1
568 查看剩余票数 1
18940 查看剩余票数 1
12868 查看剩余票数 1
5940 查看剩余票数 1
15580 购票成功
9128 查看剩余票数 0
16812 查看剩余票数 0
568 购票成功
19328 查看剩余票数 0
12868 购票成功
14440 购票成功
8640 购票成功
5940 购票成功
18940 购票成功
以上效率高,但是安全性低
使用整体串行,p.join()方法,效率过低
采取折中的方法,不是整体串行,只把修改数据的部分变成串行
使用互斥锁:
#模拟多人查票、抢票
from multiprocessing import Process,Lock
import json
import time
import random
import os
def search():
time.sleep(random.randint(1,3))
dic=json.load(open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','r',encoding='utf-8'))
print('%s 查看剩余票数 %s' %(os.getpid(),dic['count']))
def get():
dic=json.load(open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','r',encoding='utf-8'))
if dic['count']>0:
dic['count']-=1
time.sleep(random.randint(1,3))
json.dump(dic,open(r'C:\Users\clt\Anaconda3\lettycode\db.txt','w',encoding='utf-8')) #将买完票写回
print('%s 购票成功' %os.getpid() )
def task(mutex): #互斥锁仅使得修改数据的地方串行,其他地方都是正常
mutex.acquire() #加锁
search()
get()
mutex.release() #解锁
if __name__=='__main__':
mutex=Lock()
for i in range(10):
p=Process(target=task,args=(mutex,)) #为了让10个进程同用一把锁,将该锁当做参数传过去
p.start()
结果:
8160 查看剩余票数 1
8160 购票成功
12112 查看剩余票数 0
14820 查看剩余票数 0
2948 查看剩余票数 0
18004 查看剩余票数 0
8988 查看剩余票数 0
10348 查看剩余票数 0
1340 查看剩余票数 0
15012 查看剩余票数 0
16124 查看剩余票数 0
涉及到共享问题,就涉及到竞争,就得使用互斥锁,多出地方有互斥现象就多出设锁,不能共用一把锁,使用互斥锁牺牲了效率,保证了安全性
- 进程 Queue
1、 进程通信有个专门的数据结构,叫做IPC
2、进程通信可以用文件实现:速度慢,使用硬盘资源效率低,并且需处理锁的问题比较危险
3、IPC机制不包括文件法,使用的是内存空间,包括两种:队列和管道
队列其实就是管道加锁实现,处理了自己加锁的问题,所以以后用队列
# -*- coding: utf-8 -*-
"""
Created on Sun Dec 15 09:33:05 2019
@author: clt
"""
from multiprocessing import Queue
q=Queue(3) #队列用来放消息,不应该放大数据
q.put('first') #放消息,put其实可以放任何类型的数据
q.put(2)
q.put({'count':3})
print(q.get())
print(q.get())
print(q.get())
#有三个值,如果取四个就阻塞。有三个空,如果放四个没有取也会阻塞
结果:
first
2
{'count': 3}
扩展1,满了不让其阻塞,会抛异常
from multiprocessing import Queue
q=Queue(3) #队列用来放消息,不应该放大数据
q.put('first') #放消息,put其实可以放任何类型的数据
q.put(2)
q.put({'count':3})
q.put('fourth',block=False)
结果:
raise Full
queue.Full
block=False 不让其阻塞就抛异常
q.put_nowait() 不让其阻塞就抛异常
q.put( ,block=True,timeout=3) 阻3秒,还不取,就抛异常
from multiprocessing import Queue
q=Queue(3) #队列用来放消息,不应该放大数据
q.put('first') #放消息,put其实可以放任何类型的数据
q.put(2)
q.put({'count':3})
#q.put('fourth',block=False)
q.put_nowait('fourth')
结果:
raise Full
queue.Full
from multiprocessing import Queue
q=Queue(3) #队列用来放消息,不应该放大数据
q.put('first') #放消息,put其实可以放任何类型的数据
q.put(2)
q.put({'count':3})
#q.put('fourth',block=False)
#q.put_nowait('fourth')
q.put('forth',block=True,timeout=3)
结果:
raise Full
queue.Full
#引起异常的时间慢
扩展2
取的时候,为空还取,并不让其阻塞,抛异常
from multiprocessing import Queue
q=Queue(3) #队列用来放消息,不应该放大数据
q.put('first') #放消息,put其实可以放任何类型的数据
q.put(2)
q.put({'count':3})
#q.put('fourth',block=False)
#q.put_nowait('fourth')
#q.put('forth',block=True,timeout=3)
print(q.get())
print(q.get())
print(q.get())
print(q.get(block=False))
结果:
first
2
{'count': 3}
Traceback (most recent call last):
File "C:/Users/clt/Anaconda3/lettycode/Queue.py", line 21, in <module>
print(q.get(block=False))
File "C:\Users\clt\Anaconda3\lib\multiprocessing\queues.py", line 107, in get
raise Empty
queue.Empty
同上
q.get_nowait()
q.get(block=True,timeout=3)