关于课后作业添加进程锁

关于课后作业添加进程锁

# coding:utf-8
import json
import os
import time

from common.utils import check_file, timestamp_to_str, save
from common.error import UserExistsError, RoleError, LevelError, CountError
from common.consts import ROLES, FIRST_LEVELS, SECOND_LEVELS
from multiprocessing import Lock


class Base(object):
    def __init__(self, user_json, gift_json):
        self.user_json = user_json
        self.gift_json = gift_json
        self.lock = Lock()

        self.__check_user_json()
        self.__check_gift_json()
        self.__init_gifts()

    # 文件检查
    def __check_user_json(self):
        check_file(self.user_json)

    def __check_gift_json(self):
        check_file(self.gift_json)

    # 操作user:
    # 读取users
    def __read_users(self, time_to_str=False):
        self.lock.acquire()
        try:
            with open(self.user_json, 'r', encoding='utf-8') as f:
                json_data = json.loads(f.read())

            if time_to_str:
                for k, v in json_data.items():
                    v['create_time'] = timestamp_to_str(v['create_time'])
                    v['update_time'] = timestamp_to_str(v['update_time'])
                    json_data[k] = v
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return json_data

    # 增加user
    def __write_user(self, **user):
        if 'username' not in user:
            raise ValueError('缺少username')
        if 'role' not in user:
            raise ValueError('缺少role')

        user['active'] = True
        user['create_time'] = time.time()
        user['update_time'] = time.time()
        user['gifts'] = []

        self.lock.acquire()
        try:
            users = self.__read_users()
            if user['username'] in users:
                raise UserExistsError('用户 %s 已存在' % user['username'])

            users.update(
                {user['username']: user}
            )
            save(self.user_json, users)
        except Exception as e:
            raise e
        finally:
            self.lock.release()

    # 修改role
    def __change_role(self, username, role):
        self.lock.acquire()
        try:
            users = self.__read_users()
            user = users.get(username)

            if not user:
                return False

            if role not in ROLES:
                raise RoleError('role只能是admin或者normal')

            user['role'] = role
            user['update_time'] = time.time()
            users[username] = user
            save(self.user_json, users)
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return True

    # 修改active
    def __change_active(self, username):
        self.lock.acquire()
        try:
            users = self.__read_users()
            user = users.get(username)

            if not user:
                return False

            user['active'] = not user['active']
            user['update_time'] = time.time()
            users[username] = user
            save(self.user_json, users)
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return True

    # 删除user
    def __delete_user(self, username):
        self.lock.acquire()
        try:
            users = self.__read_users()
            user = users.get(username)

            if not user:
                return False

            del_user = users.pop(username)
            save(self.user_json, users)
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return del_user

    # 操作gift
    # 读取gifts
    def __read_gifts(self):
        self.lock.acquire()
        try:
            with open(self.gift_json, 'r', encoding='utf-8') as f:
                json_gifts = json.loads(f.read())
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return json_gifts

    # gift结构初始化
    def __init_gifts(self):
        data = {
            'level1': {
                'level1': {},
                'level2': {},
                'level3': {}
            },
            'level2': {
                'level1': {},
                'level2': {},
                'level3': {}
            },
            'level3': {
                'level1': {},
                'level2': {},
                'level3': {}
            },
            'level4': {
                'level1': {},
                'level2': {},
                'level3': {}
            }
        }
        self.lock.acquire()
        try:
            gifts = self.__read_gifts()
            if len(gifts) != 0:
                return
            save(self.gift_json, data)
        except Exception as e:
            raise e
        finally:
            self.lock.release()

    # 判断gift等级合理性及获取gifts
    def __check_get_gifts(self, first_level, second_level):
        if first_level not in FIRST_LEVELS:
            raise LevelError('第一层level等级错误,只能是level1~level4')
        if second_level not in SECOND_LEVELS:
            raise LevelError('第二层level等级错误,只能是level1~level3')
        self.lock.acquire()
        try:
            gifts = self.__read_gifts()
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        level_one = gifts[first_level]
        level_two = level_one[second_level]
        return {
            'level_one': level_one,
            'level_two': level_two,
            'gifts': gifts
        }

    # 添加gift
    def __write_gift(self, first_level, second_level, gift_name, gift_count):
        assert isinstance(gift_count, int), '礼物数量必须是int'
        data = self.__check_get_gifts(first_level, second_level)
        gifts = data.get('gifts')
        level_one = data.get('level_one')
        level_two = data.get('level_two')

        if gift_count <= 0:
            gift_count = 1

        if gift_name in level_two:
            level_two[gift_name]['count'] = level_two[gift_name]['count'] + gift_count
        else:
            level_two[gift_name] = {
                'name': gift_name,
                'count': gift_count
            }
        level_one[second_level] = level_two
        gifts[first_level] = level_one
        self.lock.acquire()
        try:
            save(self.gift_json, gifts)
        except Exception as e:
            raise e
        finally:
            self.lock.release()

    # gift数量修改(根据gift_count数量递减)
    def __update_gift(self, first_level, second_level, gift_name, gift_count=1, is_admin=False):
        assert isinstance(gift_count, int), '礼物数量必须是int'
        data = self.__check_get_gifts(first_level, second_level)
        gifts = data.get('gifts')
        level_one = data.get('level_one')
        level_two = data.get('level_two')

        if gift_name not in level_two:
            return False

        if is_admin:
            if gift_count <= 0:
                raise CountError('礼物数量错误')
            level_two[gift_name]['count'] = gift_count
        else:
            if level_two[gift_name]['count'] - gift_count < 0:
                raise CountError('礼物数量错误')
            level_two[gift_name]['count'] -= gift_count

        level_one[second_level] = level_two
        gifts[first_level] = level_one
        self.lock.acquire()
        try:
            save(self.gift_json, gifts)
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return True

    # gift的删除
    def __delete_gift(self, first_level, second_level, gift_name):
        data = self.__check_get_gifts(first_level, second_level)
        gifts = data.get('gifts')
        level_one = data.get('level_one')
        level_two = data.get('level_two')

        if gift_name not in level_two:
            return False

        del_gift = level_two.pop(gift_name)
        level_one[second_level] = level_two
        gifts[first_level] = level_one
        self.lock.acquire()
        try:
            save(self.gift_json, gifts)
        except Exception as e:
            raise e
        finally:
            self.lock.release()
        return del_gift

请老师看一下这样添加进程锁对不对,还有请问对于读取json文件时有必要添加进程锁吗以及加锁时有必要加except代码块吗?还是只用try...finally就可以

正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

1回答
好帮手慕小猿 2023-05-22 11:46:56

同学,你好!1、同学的添加的进程锁是没有问题的。

2、读取文件时是有必要添加进程锁的,避免同一时间多人操作文件,争抢写入,有的人可能写入不上。用锁可以保证同一时间只有一个人在操作文件,保证了数据的准确性。

3、用try .....except.....finally避免报错而终止程序运行,建议使用try .....except.....finally

祝学习愉快~

  • 老师,这样加进程锁有些地方是有问题的,会出现死锁的问题,比如__read_users()函数中加了锁,然后__write_user()函数中调用__read_users()之前又加了锁,程序就不能正常运行,我又修改了一下,就只是在__read_users()、__read_gifts()以及utils模块中的save()中添加了进程锁,这样应该才是对的嘛?

    # coding:utf-8
    import json
    import multiprocessing
    import os
    import time
    
    from common import utils, consts
    from common.error import (UserExistsError, RoleError, LevelError, NegativeNumberError,
                              CountError)
    
    """
        一、
        1:确定用户表中每个用户的信息字段
        2:读取user.json文件
        3:写入user.json文件(检测该用户是否存在),存在则不可写入
            
        username:姓名
        role:normal or admin
        active:True or False
        create_time:timestamp
        update_time:timestamp
        gifts:[]
        用户信息完整格式:{username: {username: ***, role: ***, active: ***...}}
        
        二、
        1:role的修改
        2:active的修改
        3:delete_user
        
        三、
        1:gifts 奖品结构的确定
        2:gifts 奖品的读取
        3:gifts 添加
        4:gifts 初始化
        
        四、
        1:gifts 修改(数量递减)
        2:gifts 奖品删除
        
        {
            level1: {
                level1: {
                    gift_name1: {
                        name: xxx,
                        count: xxx
                    },
                    gift_name2: {
                        name: xxx,
                        count: xxx
                    }
                },
                level2: {},
                level3: {}
            },
            level2:{
                level1: {},
                level2: {},
                level3: {}
            },
            level3:{
                level1: {},
                level2: {},
                level3: {}
            },
            level4:{
                level1: {},
                level2: {},
                level3: {}
            }
        }  
          
    """
    
    
    class Base(object):
        def __init__(self, user_json, gift_json):
            self.user_json = user_json
            self.gift_json = gift_json
            self.lock = multiprocessing.Manager().Lock()
    
            self.__check_user_json()
            self.__check_gift_json()
            self.__init_gifts()
    
        def __check_user_json(self):
            utils.check_file(self.user_json)
    
        def __check_gift_json(self):
            utils.check_file(self.gift_json)
    
        def __read_users(self, time_to_str=False):
            try:
                self.lock.acquire()
                with open(self.user_json, 'r', encoding='utf-8') as f:
                    data = json.loads(f.read())
    
                if time_to_str:
                    for k, v in data.items():
                        v['create_time'] = utils.timestamp_to_string(v['create_time'])
                        v['update_time'] = utils.timestamp_to_string(v['update_time'])
                        data[k] = v
            except Exception as e:
                raise e
            finally:
                self.lock.release()
    
            return data
    
        def __write_user(self, **user):
            if 'username' not in user:
                raise ValueError('missing username')
            if 'role' not in user:
                raise ValueError('missing role')
    
            user['active'] = True
            user['create_time'] = time.time()
            user['update_time'] = time.time()
            user['gifts'] = []
    
            users = self.__read_users()
    
            if user['username'] in users:
                raise UserExistsError('username %s had exists' % user['username'])
    
            users.update(
                {user['username']: user}
            )
            utils.save(users, self.user_json, self.lock)
    
        def __change_role(self, username, role):        
            users = self.__read_users()
            user = users.get(username)  # {'username': {username: ***, role: *** ...}}
    
            if not user:
                return False
    
            if role not in consts.ROLES:
                raise RoleError('not use role %s' % role)
    
            user['role'] = role
            user['update_time'] = time.time()
            users[username] = user
            utils.save(users, self.user_json, self.lock)    
            
            return True
    
        def __change_active(self, username):        
            users = self.__read_users()
            user = users.get(username)
    
            if not user:
                return False
    
            user['active'] = not user['active']
            user['update_time'] = time.time()
            users[username] = user
            utils.save(users, self.user_json, self.lock)  
            
            return True
    
        def __delete_user(self, username):
            users = self.__read_users()
            user = users.get(username)
    
            if user is None:
                return False
    
            del_user = users.pop(username)        
            utils.save(users, self.user_json, self.lock)   
            
            return del_user
    
        def __read_gitfs(self):
            try:
                self.lock.acquire()
                with open(self.gift_json, 'r', encoding='utf-8') as f:
                    data = json.loads(f.read())
            except Exception as e:
                raise e
            finally:
                self.lock.release()
    
            return data
    
        def __init_gifts(self):
            data = {
                'level1': {
                    'level1': {},
                    'level2': {},
                    'level3': {}
                },
                'level2': {
                    'level1': {},
                    'level2': {},
                    'level3': {}
                },
                'level3': {
                    'level1': {},
                    'level2': {},
                    'level3': {}
                },
                'level4': {
                    'level1': {},
                    'level2': {},
                    'level3': {}
                }
            }
    
            gifts = self.__read_gitfs()
            
            if len(gifts) != 0:
                return
            
            utils.save(data, self.gift_json, self.lock)        
    
        def __write_gift(self, first_level, second_level, gift_name, gift_count):        
            assert isinstance(gift_count, int), 'gift count is int'
            data = self.__check_get_gift(first_level, second_level)
    
            gifts = data.get('gifts')
            first_pool = data.get('level_one')
            second_pool = data.get('level_two')
    
            if gift_count <= 0:
                gift_count = 1
    
            if gift_name in second_pool:
                second_pool[gift_name]['count'] = second_pool[gift_name]['count'] + gift_count
            else:
                second_pool[gift_name] = {
                    'name': gift_name,
                    'count': gift_count
                }
            first_pool[second_level] = second_pool
            gifts[first_level] = first_pool
            utils.save(gifts, self.gift_json, self.lock)        
    
        def __gift_update(self, first_level, second_level, gift_name, gift_count=1,
                          is_admin=False):        
            assert isinstance(gift_count, int), 'gift count is int'
            data = self.__check_get_gift(first_level, second_level)
    
            gifts = data.get('gifts')
            first_pool = data.get('level_one')
            second_pool = data.get('level_two')
    
            if gift_name not in second_pool:
                return False
    
            current_gift = second_pool[gift_name]
    
            if is_admin:
                if gift_count <= 0:
                    raise CountError('gift count must bigger 0')
                current_gift['count'] = gift_count
            else:
                if current_gift['count'] - gift_count < 0:
                    raise NegativeNumberError('gift_count can\'t negative')
                current_gift['count'] -= gift_count
            second_pool[gift_name] = current_gift
            first_pool[second_level] = second_pool
            gifts[first_level] = first_pool
            utils.save(gifts, self.gift_json, self.lock)        
    
        def __delete_gift(self, first_level, second_level, gift_name):        
            data = self.__check_get_gift(first_level, second_level)
            first_pool = data.get('level_one')
            second_pool = data.get('level_two')
            gifts = data.get('gifts')
    
            if gift_name not in second_pool:
                return False
    
            del_data = second_pool.pop(gift_name)
            first_pool[second_level] = second_pool
            gifts[first_level] = first_pool
            utils.save(gifts, self.gift_json, self.lock)
            
            return del_data
    
        def __check_get_gift(self, first_level, second_level):
            if first_level not in consts.FIRST_LEVELS:
                raise LevelError('first_level not exists')
            if second_level not in consts.SECOND_LEVELS:
                raise LevelError('second_level not exists')
    
            gitfs = self.__read_gitfs()
            level_one = gitfs.get(first_level)
            level_two = level_one.get(second_level)
    
            return {
                'level_one': level_one,
                'level_two': level_two,
                'gifts': gitfs
            }
    def save(data, path, lock):
        lock.acquire()
        json_data = json.dumps(data, ensure_ascii=False)
        with open(path, 'w', encoding='utf-8') as f:
            f.write(json_data)
        lock.release()


    2023-05-23 16:28:33
  • 同学,你好!老师理解错了同学的意思,抱歉!老师理解是问写入数据时是否需要加锁。同学问的是读取数据的时候是否需要加锁。读取数据时不需要加锁,因为都是从文件中读取数据,不存在数据修改的问题。数据没有改变谁读取都是一样的数据,所以读取可以不添加锁的。在写入数据时添加锁是必要的。因为同一时间多人改文件,有的人改完文件保存了,可能另一个人以为改的还是原来文件(其实文件已发生变化)可能会造成数据不统一的问题。所以写入的时候是需要加锁的。同学只需在_save方法写入文件时添加锁就可以的。

    https://img1.sycdn.imooc.com//climg/646c863109069c5605780414.jpg

    祝学习愉快~

    2023-05-23 17:25:17
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师