Python进程相关(二)互斥锁、进程队列

本文介绍了Python中处理进程安全的方法,重点讲解了互斥锁在模拟抢票场景中的应用,以及如何通过进程队列进行高效通信。在处理共享数据时,互斥锁能确保数据修改的串行化,提高安全性但牺牲部分效率。进程队列作为一种内存中的IPC机制,避免了文件通信的低效和锁管理的风险,提供了阻塞和非阻塞的取放元素方式。
摘要由CSDN通过智能技术生成

-互斥锁
对于模拟多人查票抢票
票数放在文件中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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值