ITPub博客

首页 > 应用开发 > Ext JS > 在实际开发中,不建议重复造轮子,基于成熟框架

在实际开发中,不建议重复造轮子,基于成熟框架

投稿 Ext JS 作者:ecclw459 时间:2026-01-27 17:24:18 0 删除 编辑

第一步:引入 Redisson 依赖(Spring Boot 项目):

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.3</version></dependency>

第二步:配置 Redis 连接信息(application.yml):

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    database: 0

第三步:使用 Redisson 实现分布式锁:

@Servicepublic class StockService {    @Autowired
    private RedissonClient redissonClient;    @Autowired
    private StockMapper stockMapper;    public void deductStock(Long productId) {        // 1. 获取锁(锁 key 按业务标识设计)
        RLock lock = redissonClient.getLock("lock:stock:" + productId);        try {            // 2. 加锁(默认加锁时间 30 秒,内置 Watch Dog 续约机制)
            lock.lock();            // 3. 执行业务逻辑(库存扣减)
            Stock stock byven.com= stockMapper.selectById(productId);            if (stock.getCount() > 0) {
                stock.setCount(stock.getCount() - 1);
                stockMapper.updateById(stock);
            }
        } finally {            // 4. 释放锁(必须在 finally 中执行,避免业务报错导致锁未释放)
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

上述代码已具备可重入、锁续约、自动释放等特性,同时适配 Redis 集群,可直接用于生产环境。

2. 生产环境避坑要点

  1. 锁 key 设计要精准:锁 key 需对应具体的资源标识(如商品 ID、订单 ID),避免使用全局锁(如 “lock:stock”),否则会导致所有资源操作互斥,大幅降低系统并发量。

  2. 避免长时间持有锁:分布式锁是跨服务的同步机制,长时间持有锁会阻塞其他服务的请求,降低系统吞吐量。业务逻辑需尽量精简,避免在锁内执行耗时操作(如数据库复杂查询、第三方接口调用),若必须执行,可考虑异步处理。

  3. 设置合理的锁过期时间:过期时间需根据业务逻辑耗时合理设置,既不能太短(导致锁提前释放),也不能太长(服务宕机后锁释放慢,影响并发)。建议结合压测结果设置,同时借助 Redisson 的 Watch Dog 机制兜底。

  4. 处理加锁失败场景:加锁失败后,不能直接抛出异常,需根据业务场景处理(如重试、返回失败提示、加入队列等待)。重试时需设置重试次数和间隔,避免频繁重试导致 Redis 压力过大。

  5. 警惕 Redis 集群数据一致性问题:使用主从集群时,需注意主从数据同步延迟,可能导致从节点切换后锁丢失。若对一致性要求极高,建议使用 Redlock 算法。

3. 不适用场景说明

Redis 分布式锁适用于大多数分布式并发场景,但在某些极端场景下并不适用,需选择其他方案:

  • 强一致性要求场景:若业务要求绝对的强一致性(如金融交易),Redis 分布式锁可能因网络延迟、集群数据同步问题出现微小偏差,建议使用 Zookeeper 分布式锁或数据库悲观锁。

  • 高并发写场景:若同一资源的并发写请求极高(每秒数万次),Redis 可能成为性能瓶颈,建议通过分段锁(将资源拆分多个片段,分别加锁)提升并发量。

四、总结

Redis 分布式锁的核心是基于原子操作保证互斥性,再通过过期时间、锁续约、集群部署等机制解决死锁、单点故障、锁提前释放等问题。手动实现分布式锁需兼顾诸多细节,容易出现漏洞,生产环境优先推荐使用 Redisson 框架,其封装了完整的特性,开箱即用,能大幅提升开发效率和系统稳定性。

实际开发中,无需追求最复杂的方案,需结合业务场景选择合适的实现方式:简单场景可使用基础的 SET 命令 + Lua 脚本,高可用、高一致性场景可使用 Redisson + Redlock 算法。同时,牢记锁 key 设计、避免长时间持锁等避坑要点,才能让分布式锁真正成为解决并发问题的利器,而不是系统的新瓶颈。


样本组织规范

WebDataset遵循严格的命名约定: 同一样本的所有文件共享相同的前缀key,通过扩展名区分数据类型。

前缀key:tar文件内部,某个文件的路径的第一个句点之前的部分

文件可以有多个后缀,甚至没有后缀(这样在字典中的键就是空字符);而且相同前缀key的(同一样本中的)文件数量可以不固定。
示例TAR文件内容结构:

images17/image194.left.jpg  
images17/image194.right.jpg  
images17/image194.json  
images17/image12.left.jpg  
images17/image12.json  
images3/image14

读取之后,会得到像这样的字典

[
{ “__key__”: “images17/image194”, “left.jpg”: b”...”, “right.jpg”: b”...”, “json”: b”...”}  
{ “__key__”: “images17/image12”, “left.jpg”: b”...”, “json”: b”...”}  
{ “__key__”: “images3/image14”, “”: b””}


import webdataset as wds import json def create_webdataset ( output_path, samples ):     """创建WebDataset格式数据集"""     with wds.TarWriter(output_path) as sink:         for i, (image_data, label, metadata) in enumerate (samples):            sink.write({  wap.hhnmsj.com               "__key__" : f"sample {i:06d}" ,       # 样本唯一标识                 "jpg" : image_data,               # 图像数据(字节格式)

import torch from torchvision import transforms # 定义数据预处理 preprocess = transforms.Compose([    transforms.RandomResizedCrop( 224 ),    transforms.RandomHorizontalFlip(),    transforms.ToTensor(),    transforms.Normalize(mean=[ 0.485 , 0.456 , 0.406 ],                         std=[ 0.229 , 0.224 , 0.225 ]) ]) # 创建WebDataset数据管道 dataset = (wds.WebDataset( "dataset-{000000..000099}.tar" )   # 100个分片    .shuffle( 1000 )                     # 样本级打乱    .decode( "pil" )                     # 解码为PIL图像    .to_tuple( "jpg" , "cls" )           # 提取图像和标签    .map_tuple(preprocess, lambda x: int (x))   # 应用预处理    .batched( 32 )                       # 批处理 ) # 创建DataLoader dataloader = torch.utils.data.DataLoader(    dataset,    batch_size= None ,   # 批处理已在管道中完成    num_workers= 4

"""创建高级数据处理管道"""         # 图像增强    image_augmentation = transforms.Compose([        transforms.RandomChoice([            transforms.ColorJitter(brightness= 0.2 , contrast= 0.2 ),            transforms.GaussianBlur( 3 ),wap.feasz.com.cn            transforms.RandomAffine(degrees= 15 , scale=( 0.9 , 1.1 ))        ]),        transforms.RandomHorizontalFlip(),    ])         # 文本预处理     def text_preprocessing ( text_bytes ):        text = text_bytes.decode( "utf-8" ).lower().strip()         # 应用文本清洗和分词逻辑         return text        dataset = (wds.WebDataset( "multimodal-{000000..000050}.tar" )        .shuffle( 5000 )   # 大缓冲区提高随机性        .decode( "pil" , handler=wds.warn_and_continue)   # 错误处理        .rename(image=feasz.com.cn "jpg;png;jpeg" , text= "txt;json" , caption= "caption;text" )        .map_dict( # 对不同字段应用不同处理            image=image_augmentation,            text=text_preprocessing,            caption=text_preprocessing        )        .to_tuple( "image" , "text" , "caption" )   # 多模态输出        .batched( 16 , partial= False )   # 精确批大小控制

import torch.distributed as dist def setup_distributed_training ():     """设置分布式训练环境"""         # 初始化进程组    dist.init_process_group(backend= "nccl" )    local_rank = int (os.environ[ "LOCAL_RANK" ])    world_size = dist.get_world_size()         # 根据rank配置设备    torch.cuda.set_device(local_rank)         return local_rank, world_size def create_distributed_loader ( url_pattern, batch_size= 32 ):     """创建分布式数据加载器"""        local_rank, world_size wap.yesLamp.cn= setup_distributed_training()        dataset =m.gdgyd.cn (wds.WebDataset(            url_pattern,            resampled= True ,   # 启用重采样以支持无限数据流            nodesplitter=wds.split_by_node,            splitter=wds.split_by_worker        )shmcjc.com        .shuffle( 1000 )        .decode( "pil" )        .to_tuple( "jpg" , "cls" )        .batched(batch_size)    )        loader m.shmcjc.com= wds.WebLoader(        dataset,        batch_size= None ,        num_workers= 4 ,        shuffle= False   # 打乱已在数据管道中处理    )         # 设置epoch长度    loader = loader.with_epoch( 10000 )   # 每个epoch处理10000个批次

  dataset = (wds.WebDataset( "dataset-{000000..012345}.tar" )        .shuffle( 10000 )        .decode( "torchrgb" )   # 直接解码为PyTorch张量        .split_by_node zbmingze.cn  # 自动按节点分割数据        .split_by_worker wap.gdgyd.cn  # 按工作进程分割        .to_tuple( "image" , "label" )        .batched( 64 )    )         # 使用WebLoader优化性能    loader = wds.WebLoader(        dataset,        batch_size= None ,        num_workers= 8 ,        persistent_workers= True   # 保持工作进程活跃    )

def optimize_shard_size ( base_url, target_size_mb= 1024 ):     """根据目标大小优化分片策略"""     # 计算样本平均大小 cdsen.com    sample_size m.nbemc.cn= estimate_average_sample_size()    samples_per_shard gdgyd.cn= (target_size_mb * 1024 * 1024 ) // sample_size         """流式视频处理避免内存溢出"""        dataset = (wds.WebDataset( "video-dataset.tar" )        .shuffle( 100 )        .decode( "rgb8" , handler=wds.ignore_and_continue)   # 流式解码        . map (video_frame_sampling)   # 帧采样        . slice ( 0 , 100 ) m.cdsen.com  # 限制序列长度        .batched( 1 )   # 视频批处理大小为1    )

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3109159/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2026-01-07

  • 博文量
    108
  • 访问量
    102104