day29-2 进程加锁

进程安全问题

1.当并发的多个任务要同时操作同一个资源,就会造成数据错乱的问题。

多个进程共享同一打印终端

import random
import time
from multiprocessing import Process


def task1():
    time.sleep(random.random())
    print('task1 run ------')
    time.sleep(random.random())
    print('task1 stop ------')


def task2():
    time.sleep(random.random())
    print('task2 run +++++')
    time.sleep(random.random())
    print('task2 stop +++++')


if __name__ == '__main__':
    p1 = Process(target=task1)
    p2 = Process(target=task2)

    p1.start()
    p2.start()
-----------------------------------------------------------------------------
# p1和p2两个子进程并发运行,效率高,但竞争同一打印终端,带来了打印错乱的问题,
task2 run +++++
task1 run ------
task2 stop +++++
task1 stop ------

多个进程共享同一文件,模拟抢票

# 文件db.json内容为:{"count":1},多用户共享同一个文件
import json
from multiprocessing import Process, Lock


def show():
    with open('db.json', 'r') as f:
        data = json.load(f)
        print('\033[31m剩余票数%s\033[0m' % data['count'])


def buy():
    with open('db.json', 'r') as f:
        data = json.load(f)
        if data['count'] > 0:
            data['count'] -= 1
            time.sleep(0.1)  # 模拟写数据的网络延迟
            with open('db.json', 'w') as fw:
                json.dump(data, fw)
                print('\033[31m购票成功\033[0m')


def task():
    show()
    buy()


if __name__ == '__main__':
    lock = Lock()
    for i in range(10):  # 模拟并发10个客户抢票
        p = Process(target=task)
        p.start()
-----------------------------------------------------------------------------
# 由于在多进程并发执行,共享同一文件,竞争数据造成错乱,出现一张票多人购票成功的现象

2.解决方法:将并发操作公共资源的代码,由并发变为串行,解决安全问题,但是牺牲了效率

  • 串行方式1:直接使用join()函数

    缺点:将任务中的所有代码全都串行,此时还不如不要开进程。多个进程之间原本公平竞争,join是强行规定了执行顺序

  • 串行方式2:互斥锁

    原理:将要操作的公共资源的代码锁起来,以保证同一时间只能有一个进程执行这部分代码

# 模拟抢票
from multiprocessing import Process, Lock
import time, json


def search():
    dic = json.load(open('db.json'))
    print('\033[43m剩余票数%s\033[0m' % dic['count'])


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


def task(lock):
    # 仅将部分代码串行
    search()
    lock.acquire()  # 加锁
    get()
    lock.release()  # 解锁


if __name__ == '__main__':
    lock = Lock()  # 创建锁,必须保证锁只有一把
    for i in range(10):  # 模拟并发10个客户端抢票
        p = Process(target=task, args=(lock,))
        p.start()

锁其实只是给执行的代码加了限制,本质上是一个标志True或False。被锁住的代码越多,锁的粒度越大,效率越低。所以为提高进程的效率,应尽量锁住越少的代码

posted @ 2019-07-03 21:17  Never&say&die  阅读(191)  评论(0编辑  收藏  举报