111 python程序中的进程操作-多进程同步(mulitProcessing Lock锁)

Posted xichenhome

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了111 python程序中的进程操作-多进程同步(mulitProcessing Lock锁)相关的知识,希望对你有一定的参考价值。

通过学习,我们使用各种方法实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。

一、锁的基础使用

1.1多个进程抢占数据资源

from multiprocessing import Process
import os
import time
import random

def work(n):
    print(f'n,os.getpid()is running')
    time.sleep(random.random())
    print(f'n,os.getpid() is end')

if __name__ == '__main__':
    for i in range(1,4):
        p = Process(target=work,args=(i,))
        p.start()

(1, 4212)is running
(2, 8856)is running
(3, 5680)is running
(3, 5680) is end
(1, 4212) is end
(2, 8856) is end

1.2使用锁维护执行顺序

from multiprocessing import Process,Lock
import os
import time
import random

def work(n,lock):
    lock.acquire()
    print(f'n,os.getpid()is running')
    time.sleep(random.random())
    print(f'n,os.getpid() is end')
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    for i in range(1,4):
        p = Process(target=work,args=(i,lock))
        p.start()

(1, 13304)is running
(1, 13304) is end
(2, 7524)is running
(2, 7524) is end
(3, 14552)is running
(3, 14552) is end

上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。

三、抢票小程序实列(锁实现数据安全和高效率)

3.1多进程同时抢票实例

我们以模拟抢票为例,来看看数据安全的重要性。

# 文件db的内容为:"count":1
# 注意一定要用双引号,不然json无法识别
# 并发运行,效率高,但竞争写同一文件,数据写入错乱
from multiprocessing import Process,Lock
import time,json,random
def search(i):
    time.sleep(1)
    dic=json.load(open('ad.txt'))
    print('子进程%s查看剩余票数%s' %(i,dic['count']))

def get():
    dic=json.load(open('ad.txt'))
    time.sleep(1)  # 模拟读数据的网络延迟
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(0.2)  # 模拟写数据的网络延迟
        json.dump(dic,open('ad.txt','w'))
        print('购票成功')

def task(i):
    search(i)
    get()

if __name__ == '__main__':
    for i in range(1,15):  # 模拟并发15个客户端抢票
        p=Process(target=task,args=(i,))
        p.start()

子进程2查看剩余票数1
子进程3查看剩余票数1
子进程12查看剩余票数1
子进程7查看剩余票数1
子进程11查看剩余票数1
子进程13查看剩余票数1
子进程9查看剩余票数1
子进程8查看剩余票数1
子进程6查看剩余票数1
子进程14查看剩余票数1
子进程5查看剩余票数1
子进程1查看剩余票数1
子进程10查看剩余票数1
子进程4查看剩余票数1
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功

并发运行,效率高,但竞争写同一文件,数据写入错乱

3.2 使用join方法来实现数据安全

如果使用join方法的话,那这样就是成了一个串行的概念了,这样只能保证数据的安全性,但是程序的效率问题并没有解决

from multiprocessing import Process,Lock
import time,json,random
def search():
    dic=json.load(open('db'))
    print('剩余票数%s' %dic['count'])

def get():
    dic=json.load(open('db'))
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(0.2)  # 模拟写数据的网络延迟
        json.dump(dic,open('db','w'))
        print('购票成功')

def task():
    search()
    get()

if __name__ == '__main__':
    for i in range(1,15):  # 模拟并发15个客户端抢票
        p=Process(target=task)
        p.start()
        p.join()

子进程1查看剩余票数1
购票成功
子进程2查看剩余票数0
没有票了
子进程3查看剩余票数0
没有票了
子进程4查看剩余票数0
没有票了
子进程5查看剩余票数0
没有票了
子进程6查看剩余票数0
没有票了
子进程7查看剩余票数0
没有票了
子进程8查看剩余票数0
没有票了
子进程9查看剩余票数0
没有票了
子进程10查看剩余票数0
没有票了
子进程11查看剩余票数0
没有票了
子进程12查看剩余票数0
没有票了
子进程13查看剩余票数0
没有票了
子进程14查看剩余票数0
没有票了

*3.3 使用锁机制Lock来实现数据安全

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。

import json
import time
from multiprocessing import Process, Lock

def check():
    with open('db.txt','r',encoding='utf8') as fr:
        res = json.load(fr)
        return res

def buy(i):
    with open('db.txt','r',encoding='utf8') as fr:
        res = json.load(fr)
    time.sleep(1)
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt','w',encoding='utf8') as fw:
            json.dump(res,fw)
            print(f'进程i抢票成功')
        time.sleep(0.5) # 模拟网络io
    else:
        print(f'票已经售空!!!!')

def test(i,lock):
    res = check()
    print(f'还剩res["count"]张票!')

    lock.acquire() # 相当于锁头。锁住
    buy(i)
    lock.release() # 释放锁头

if __name__ == '__main__':
    lock = Lock() # 写在这里是为了每一个进程都拿到的是同一把锁
    for i in range(1,10):# 并发模拟10个子进程同时抢票
        p = Process(target=test,args=(i,lock))
        p.start()


        # 进程锁,是把锁住的代码编程了串行
        # join 是把所有的子进程编程了串行

还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
还剩1张票!
进程5抢票成功
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!

以上是关于111 python程序中的进程操作-多进程同步(mulitProcessing Lock锁)的主要内容,如果未能解决你的问题,请参考以下文章

Python程序中的进程操作-进程同步(multiprocess.Lock)

python-协程多线程多进程性能比较

110 python程序中的进程操作-开启多进程

122 Python程序中的多进程和多线程

Python程序中的进程操作-开启多进程(multiprocess.process)

python多进程和多线程