首页 > 编程语言 >python 协程 自定义互斥锁

python 协程 自定义互斥锁

时间:2024-07-25 23:28:28浏览次数:14  
标签:__ 自定义 python order 互斥 user datetime id asyncio

最近在用python的一款异步web框架sanic搭建web服务,遇到一个需要加特定锁的场景:同一用户并发处理订单时需要排队处理,但不同用户不需要排队。

如果仅仅使用async with asyncio.Lock()的话。会使所有请求都排队处理。

 1 import asyncio
 2 import datetime
 3 
 4 lock = asyncio.Lock()
 5 
 6 
 7 async def place_order(user_id, order_id):
 8     async with lock:
 9         # 模拟下单处理
10         print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Processing order {order_id} for user {user_id}")
11         await asyncio.sleep(1)  # 假设处理需要 1 秒
12         print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Order {order_id} for user {user_id} is done")
13 
14 
15 # 定义一个测试函数
16 async def test():
17     # 创建四个任务,模拟两个 UserID 的并发请求
18     tasks = [
19         asyncio.create_task(place_order(1, 101)),
20         asyncio.create_task(place_order(1, 102)),
21         asyncio.create_task(place_order(2, 201)),
22         asyncio.create_task(place_order(2, 202)),
23     ]
24     # 等待所有任务完成
25     await asyncio.gather(*tasks)
26 
27 
28 if __name__ == '__main__':
29     # 运行测试函数
30     asyncio.run(test())

这显然不是想要的结果,第二种方案是定义一个字典,key使用user_id,value为asyncio.Lock(),每次执行前从字典里面获取lock,相同的user_id将会使用同一个lock,那就实现了功能。

import asyncio
import datetime

locks = {}


async def place_order(user_id, order_id):
    if user_id not in locks:
        locks[user_id] = asyncio.Lock()
    async with locks[user_id]:
        # 模拟下单处理
        print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Processing order {order_id} for user {user_id}")
        await asyncio.sleep(1)  # 假设处理需要 1 秒
        print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Order {order_id} for user {user_id} is done")


# 定义一个测试函数
async def test():
    # 创建四个任务,模拟两个 UserID 的并发请求
    tasks = [
        asyncio.create_task(place_order(1, 101)),
        asyncio.create_task(place_order(1, 102)),
        asyncio.create_task(place_order(2, 201)),
        asyncio.create_task(place_order(2, 202)),
    ]
    # 等待所有任务完成
    await asyncio.gather(*tasks)


if __name__ == '__main__':
    # 运行测试函数
    asyncio.run(test())

但是这个方案会有缺点是,user_id执行完成之后没有释放资源,当请求的user_id变多之后,势必会造成占用过多的资源。继续改进方案,将locks的value加一个计数器,当获取lock时计数器加1,使用完之后计数器-1,当计数器变为小于等于0时,释放locks对应的key。最后将这个功能封装为一个类方便其他地方调用。

import asyncio

mutex_locks = {}


class MutexObj:
    def __init__(self):
        self.lock = asyncio.Lock()
        self.count = 0


class Mutex:
    def __init__(self, key: str):
        if key not in mutex_locks:
            mutex_locks[key] = MutexObj()
        self.__mutex_obj = mutex_locks[key]
        self.__key = key

    def lock(self):
        """
        获取锁
        :return:
        """
        self.__mutex_obj.count += 1
        return self.__mutex_obj.lock

    def release(self):
        """
        释放锁
        :return:
        """
        self.__mutex_obj.count -= 1
        if self.__mutex_obj.count <= 0:
            del mutex_locks[self.__key]
import asyncio
import datetime

from utils.mutex import Mutex, mutex_locks

locks = {}


async def place_order(user_id, order_id):
    mutex = Mutex(user_id)
    async with mutex.lock():
        try:
            # 模拟下单处理
            print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Processing order {order_id} for user {user_id}")
            await asyncio.sleep(1)  # 假设处理需要 1 秒
            print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S:%f')} Order {order_id} for user {user_id} is done")
        except Exception as ex:
            print(ex)
        finally:
            mutex.release()
            print('=====================')
            print(mutex_locks)
            print('=====================')


# 定义一个测试函数
async def test():
    # 创建四个任务,模拟两个 UserID 的并发请求
    tasks = [
        asyncio.create_task(place_order(1, 101)),
        asyncio.create_task(place_order(1, 102)),
        asyncio.create_task(place_order(2, 201)),
        asyncio.create_task(place_order(2, 202)),
    ]
    # 等待所有任务完成
    await asyncio.gather(*tasks)


if __name__ == '__main__':
    # 运行测试函数
    asyncio.run(test())

至此实现了我的需求,此方案只考虑了单应用场景,如果是分布式部署,需要更换方案如redis锁,这里暂且不考虑。如果有其他实现方式,欢迎留言交流。

标签:__,自定义,python,order,互斥,user,datetime,id,asyncio
From: https://www.cnblogs.com/bookobe/p/18324354

相关文章

  • 企业级开源自定义表单优点多吗?好用吗?
    当前,应用专业的低代码技术平台能实现降本、增效、提质的目的。什么样的服务商能提供低代码技术平台?可以了解流辰信息企业级开源自定义表单的主要优势特点。它操作起来更灵活、更可靠、维护也方便、可视化操作界面,是很多中大型企业实现流程化办公的理想表单。欢迎随时来了解企业级......
  • Python 获取tiktok视频评论回复数据 api接口
    TIKTOKapi接口爬取tiktok视频评论回复数据详细采集页面如图https://www.tiktok.com/@dailymail/video/7329872821990182190?q=neural%20link&t=1706783508149请求APIhttp://api.xxxx.com/tt/video/info/comment/reply?video_id=7288909913185701125&comment_id=7294900......
  • Shopee虾皮api python获取虾皮购物平台的商品数据信息 数据采集
    虾皮购物(英语:Shopee)是一个电商平台,总公司设在新加坡,归属于SeaGroup(之前称之为Garena),该企业于2009年由李小冬(ForrestLi)创办。虾皮购物于2015年初次在新加坡推出,现阶段已拓展到马来西亚、泰国、印度尼西亚、越南和菲律宾。虾皮购物为全球华人地区的客户提供线上购物和销售......
  • python实现图像特征提取算法1
    python实现Marr-Hildreth算法、Canny边缘检测器算法1.Marr-Hildreth算法详解算法步骤公式Python实现详细解释优缺点2.Canny边缘检测器算法详解算法步骤公式Python实现详细解释优缺点1.Marr-Hildreth算法详解Marr-Hildreth算法是一个......
  • python实现盲反卷积算法
    python实现盲反卷积算法盲反卷积算法算法原理算法实现Python实现详细解释优缺点应用领域盲反卷积算法盲反卷积算法是一种图像复原技术,用于在没有先验知识或仅有有限信息的情况下,估计模糊图像的原始清晰图像和点扩散函数(PSF)。盲反卷积在摄影、医学成......
  • 实现一个自己的OpenFeign 远程调用验证协议--Springboot 自定义拦截器验证请求合法性-
    Springboot如何实现一个自定义的拦截器处理系统发出的请求以及接收到的请求(实现一个用于feign远程调用验证的简单协议)文章目录Springboot如何实现一个自定义的拦截器处理系统发出的请求以及接收到的请求(实现一个用于feign远程调用验证的简单协议)**实现Feign拦截器的意......
  • Python——异常捕获,传递及其抛出操作
    01.异常的概念1.程序在运行时,如果python解释器遇到一个错误,会停止程序的执行,并且提示一些错误信息,这就是异常。2.程序停止执行并且提示错误信息这个动作,我们通常称之为:抛出(raise)异常。 程序开发时,很难将所有的特殊情况都处理的面面俱到,通过异常捕获可以针对突发事件做......
  • Python 多进程下日志打印
    Python多进程下日志打印问题分析使用gunicorn启动Flask时,如果直接使用logging的RotatingFileHandler模块会出现日志混乱,甚至日志丢失的情况。在日志翻转时,可能出现一个进程将log文件翻转,而后又有进程也将log文件翻转,导致log.1文件并未达到设置的最大的文件大小,......
  • python 装饰器执行顺序的代码示例
    defdecoratorA(func):print(33)defwrapperA():print("EnteringA")print(func())print("ExitingA")print(44)returnwrapperAdefdecoratorB(func):print(11)defwrapperB():print("Ent......
  • 自定义IPython启动:打造个性化的交互式编程环境
    自定义IPython启动:打造个性化的交互式编程环境IPython,一个强大的交互式Python解释器,提供了丰富的定制选项,允许用户根据个人或团队的需求定制其行为和外观。设置自定义的启动命令是IPython定制功能的一部分,它可以让你在启动IPython时自动执行一系列操作,如导入模块、设置变量......