八:分布式锁

news2024/11/18 13:49:47

1、为什么要使用分布式锁

  1. 锁是多线程代码中的概念,只有多任务访问同一个互斥的共享资源时才需要锁。
  2. 单机应用开发时一般使用synchronizedlock。多线程的运行都是在同一个JVM之下。
  3. 应用是分布式集群,属于多JVM的工作环境,JVM之间已经无法通过多线程的锁解决同步问题。

 

2、分布式锁的几种方式

分布式锁的核心思路是借助外力 解决多JVM进程操作共享数据时需要使用互斥锁的问题。

常见的方式 有:

  1. mysql数据库分布式锁
  2. zookeeper分布式锁
  3. redis分布式锁

3、搭建测试分布式锁的环境

【1】创建工程distributed-lock-study ,pom如下

父工程

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lyx</groupId>
    <artifactId>distributed-lock-study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>distributed-lock-study</name>
    <description>distributed-lock-study</description>
    <modules>
        <module>moduleA</module>
        <module>moduleB</module>
    </modules>
    <properties>
        <java.version>8</java.version>
        <dubbo.starter>2.7.6</dubbo.starter>
        <dubbo.registry.zookeeper>2.7.6</dubbo.registry.zookeeper>
        <mysql-connection.version>8.0.26</mysql-connection.version>
        <druid.version>1.2.1</druid.version>
        <mybatis-plus.version>3.5.2</mybatis-plus.version>
        <hutool.version>5.7.17</hutool.version>
    </properties>
<dependencyManagement>
    <dependencies>
        <!-- Dubbo 依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.starter}</version>
        </dependency>
        <!-- zookeeper 注册中心 依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-registry-zookeeper</artifactId>
            <version>${dubbo.registry.zookeeper}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connection.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

    </dependencies>

</dependencyManagement>

</project>

 【2】创建moduleA和moduleB两个模块

依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.lyx</groupId>
        <artifactId>distributed-lock-study</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>moduleA</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--common-pool-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!--  Redisson分布式锁使用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.14.0</version>
        </dependency>
        <!--基于Curator 客户端(zookeeper的)实现分布式锁 -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

 【3】在两个模块中编写application.yml

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/lock_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  redis:
    host: 192.168.184.200
    port: 6379
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms
server:
  port: 1111 # 两个模块的端口号不一样,其他一样

【4】编写启动类

@SpringBootApplication
@MapperScan("top.psjj.ma.mapper")
public class ModuleAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ModuleAApplication.class,args);
    }
}

 【5】准备数据库local_db,并出入下张表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_goods
-- ----------------------------
DROP TABLE IF EXISTS `t_goods`;
CREATE TABLE `t_goods`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `goods` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
  `count` int(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_goods
-- ----------------------------
INSERT INTO `t_goods` VALUES (1, '手机', -1);
INSERT INTO `t_goods` VALUES (2, '笔记本', 100);

SET FOREIGN_KEY_CHECKS = 1;

 【6】编写po 、mapper 、service 、controller,两个模块代码完全一样

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_goods")
public class Goods implements Serializable {
    @Serial
    private static final long serialVersionUID = -9084934747907815210L;
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String goods;
    private Integer count;
}
public interface GoodsMapper extends BaseMapper<Goods> {
    @Update("update t_goods set count = count-1 where id=#{id}")
    void subCount(Integer id);
}
public interface GoodsService extends IService<Goods> {
    void updateGoodsCount(Integer id);
}
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    @Override
    public void updateGoodsCount(Integer id) {
        Goods goods = this.baseMapper.selectById(id);
        Integer count = goods.getCount();
        if(count>0){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            this.baseMapper.subCount(id);
        }
    }
}
@RestController
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private GoodsService goodsService;

    @RequestMapping("/update")
    public String updateGoodsCount(Integer id){
        goodsService.updateGoodsCount(id);
        return "ok";
    }
}

 

4、基于Mysql实现的分布式锁

4.1 mysql实现分布式锁原理

  • 首先单独分离出一台mysql数据库,所有服务要想操作文件(共享资源),那么必须先在mysql数据库中插入一个标志,插入标志的服务就持有了锁,并对文件进行操作
  • 操作完成后,主动删除标志进行锁释放,其余服务会一直查询数据库,看是否标志有被占用,直到没有标志占用时自己才能写入标志获取锁。

4.2  问题

  1. 如果服务(jvm1)宕机或者卡顿了,会一直持有锁未释放,造成死锁。因此需要一个监视锁进程,时刻监视锁的状态,如果超过一定时间未释放就要进行主动清理锁标记,然后供其他服务继续获取锁。
  2. 如果监视锁字段进程和jvm1同时挂掉,依旧不能解决死锁问题,于是又增加一个监视锁字段进程,这样一个进程挂掉,还有另一个监视锁字段进程可以对锁进行管理。
  3. 但是又诞生一个新的问题,两个监视进程必须进行同步,否则对于过期的情况管理存在不一致问题。

因此存在以下问题,并且方案变得很复杂:

  1. 监视锁字段进程对于锁的监视时间周期过短,仍旧会造成多售(jvm1还没处理完其持有的锁就被主动销毁,造成多个服务同时持有锁进行操作)。

  2. 监视锁字段进程对于锁的监视时间周期过长,会造成整个服务卡顿过长,吞吐低下。

  3. 多个监视锁字段进程间的同步问题

  4. 当一个jvm持有锁的时候,其余服务会一直访问数据库查看锁,会造成其余jvm的资源浪费

4.2 基于update实现分布锁(特殊情况)

关于分布式锁,因为代码直接执行语句,有数据库行级锁,不会产生超卖问题。

mysql行锁解决分布锁问题演示修改的代码: 

ServiceImpl中:

//mysql行锁解决分布锁问题
try {
    Thread.sleep(5000);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}
this.baseMapper.subCount2(goods);

mapper中: 

@Update("update t_goods set count=count-1 where id=#{id} and count>0")
void subCount2(Goods goods);

 

5、基于Redis实现分布式锁

 

5.1 Redis实现分布式锁优点

(1)Redis有很高的性能; 

(2)Redis命令对此支持较好,实现起来比较方便

命令介绍:

setnx :

SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。

expire :

expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。

delete :

 delete key:删除key

 在使用Redis实现分布式锁的时候,主要就会使用到这三个命令。

 

5.2 Redis实现分布式锁原理

  1. 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
  2. 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
  3. 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放

 

5.3 Redisson分布式锁使用

1)引入依赖

<!--  Redisson分布式锁使用-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

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

2)配置文件

spring:
  redis:
    host: 192.168.220.110
    port: 6379

3)代码实现

//创建锁
RLock lock = redissonClient.getLock("goods-" + id);
//加锁
try {
    lock.lock();
    Goods goods = this.baseMapper.selectById(id);
    Integer count = goods.getCount();
    if(count>0){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        this.baseMapper.subCount(id);
    }
} catch (RuntimeException e) {
    throw new RuntimeException("超卖了");
} finally {
    //释放锁
    lock.unlock();
}

5.4 总结

可以使用缓存代替数据库实现分布式锁,性能根号。同时多数缓存服务时集群部署,可以避免单点问题。

很多缓存服务提供了实现分布式锁的方法和对数据过期自动删除的支持,如Tair的put方法,redis 的setnx方法(Redisson是Redis官方推荐的Java版的Redis客户端) 。可以设置超时时间控制锁的释放。

使用缓存实现分布式锁的优点:性能好,实现起来较为方便。

使用缓存实现分布式锁的缺点通过超时时间来控制所得失效时间不靠谱。

6、 基于Zookeeper实现的分布式锁

6.1 Zookeeper的特点

Zookeeper的每一个节点,都是一个天然的顺序发号器,zookeeper有以下特点:

  1. 维护了一个有层次的数据节点,类似文件系统。

  2. 有临时节点,持久节点,临时有序节点(分布式锁实现基于的数据节点) ,持久有序节点。

  3. zookeeper可以和client客户端通过心跳机制保持长连接,断开连接自动删除临时节点。

  4. zookeeper的节点上可以注册上用户事件(自定义),节点数据删除等事件都可以触发自定义事件。

  5. zookeeper保持了统一视图,各服务对于状态信息获取满足一致性。

创建有序节点会有编号:

6.2 Zookeeper实现分布式锁原理

  1. 创建一个目录mylock;

  2. 线程A想获取锁就在mylock目录下创建临时顺序节点;

  3. 获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;

  4. 线程B获取所有节点,判断自己不是最小节点,设置监听比自己小的节点;

  5. 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

6.3 Zookeeper解决的问题

锁无法释放?

在创建锁的时候,客户端会在ZK中创建一个临时节点,一旦客户端获取到锁之后突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉锁就会释放

非阻塞锁?

客户端可以通过在ZK中创建顺序节点,并且在节点上绑定监听器,一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是序号最小,如果是,那么自己就获取到锁。

不可重入?  

客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中下次想要获取锁的时候和当前最小的节点中的数据比对。如果信息一样直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。

单点问题?

ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。  

6.4 基于Curator 客户端实现分布式锁

Curator Framework提供了简化使用zookeeper更高级的API接口。它包涵很多优秀的特性,主要包括以下三点

  1. 自动连接管理:自动处理zookeeper的连接和重试存在一些潜在的问题;可以watch NodeDataChanged event和获取updateServerList;Watches可以自动被Cruator recipes删除;

  2. 更干净的API:简化raw zookeeper方法,事件等;提供现代流式API接口

  3. Recipe实现:leader选举,分布式锁,path缓存,和watcher,分布式队列等。

 依赖:

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.0.1</version>
</dependency>

代码:

//zookeeper 分布式锁解决超卖问题
//1.创建zookeeper连接
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client= CuratorFrameworkFactory.newClient("192.168.184.200:2181", retryPolicy);
client.start();
//创建分布式锁
InterProcessMutex interProcessMutex = new InterProcessMutex(client,"/ordersettinglock");
//加锁
try {
    interProcessMutex.acquire();
    Goods goods = this.baseMapper.selectById(id);
    Integer count = goods.getCount();
    if(count>0){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        this.baseMapper.subCount(id);
    }
} catch (Exception e) {
    throw new RuntimeException("超卖了");
} finally {
    //释放锁
    try {
        interProcessMutex.release();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

6.5 总结

优点:

有效的解决单点问题、不可重入问题、非阻塞问题、锁无法释放问题。实现起来简单。

缺点:

性能上不如使用缓存实现分布式锁。需要对ZK的原理有所了解,比较复杂

7、分布式锁总结

上面几种方式,哪种方式都无法做到完美。就像CAP一样,在复杂性、可靠性、性能等方面无法同时满足,所以,根据不同的应用场景选择最适合自己的才是王道。

理解难易程度:

数据库>缓存(redis) >zookeeper.

复杂性:

zookeeper  >= 缓存 > 数据库

性能:

缓存 > zookeeper >= 数据库

可靠性:
zookeeper > 缓存 >数据库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1384926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Golang开源项目】Golang高性能内存缓存库BigCache设计与分析

项目地址 BigCache 是一个快速&#xff0c;支持并发访问&#xff0c;自淘汰的内存型缓存&#xff0c;可以在存储大量元素时依然保持高性能。BigCache将元素保存在堆上却避免了GC的开销。 背景介绍 BigCache的作者在项目里遇到了如下的需求&#xff1a; 支持http协议支持 10…

【RT-DETR改进涨点】为什么YOLO版本的RT-DETR训练模型不收敛的问题

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 其中提到的多个版本ResNet18、ResNet34、ResNet50、ResNet101为本人根据RT-…

Linux|centos7操作系统|VMware虚拟机安装水星免驱USB网卡8188gu记录

引言&#xff1a; 最近对于嵌入式系统比较感兴趣&#xff0c;因此&#xff0c;计划先使用VMware workstation虚拟机试一试Linux系统下的网卡驱动安装 这不试不知道&#xff0c;一试吓一跳&#xff0c;发现Linux下的驱动安装还是比较麻烦的&#xff0c;下面将就本次的Linux系统…

详解SpringCloud微服务技术栈:强推!源码跟踪分析Ribbon负载均衡原理、Eureka服务部署

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;详解SpringCloud微服务技术栈&#xff1a;认识微服务、服务拆分与远程调用 &#x1f4da;订阅专栏&#xff1a;微服务技术全家桶…

【LangChain学习之旅】—(6) 提示工程(下):用思维链和思维树提升模型思考质量

【LangChain学习之旅】—&#xff08;6&#xff09; 提示工程&#xff08;下&#xff09;&#xff1a;用思维链和思维树提升模型思考质量 什么是 Chain of ThoughtFew-Shot CoTZero-Shot CoTChain of Thought 实战CoT 的模板设计程序的完整框架Tree of Thought总结 Reference&a…

UE5 伤害数字跳出

学习视频 大体思路&#xff1a; 1.创建一个控件蓝图。 播放动画&#xff0c;K透明度&#xff0c;文本位置。 2.创建一个控件组件。 类默认值中设置。 3.在位置处创建组件实例 自定义事件略。

NVIDIA Isaac Sim 入门教程(一)

系列文章目录 前言 一、 NVIDIA Omniverse™ Isaac Sim 是什么&#xff1f; NVIDIA Omniverse™ Isaac Sim 是一款适用于 NVIDIA Omniverse™ 平台的机器人仿真工具包。Isaac Sim 具有构建虚拟机器人世界和实验的基本功能。它为研究人员和从业人员提供了创建稳健、物理精确的仿…

无法解析服务器的名称或地址/Wsl/0x80072eff/win10 WSL2问题解决Wsl 0x800701bc/Wsl:0x80041002

无法解析服务器的名称或地址 和 Wsl/0x80072eff 1.连VPN&#xff0c;推荐的VPN如下。(如一直显示无法连接&#xff0c;则推荐使用VPN) Anycast加速器 (any4ga.com) 优点&#xff1a;无限GB 缺点&#xff1a;较贵&#xff0c;通过银行卡充值9折后的价格是每月45元左右 …

JVM:双亲委派机制类加载器

JVM&#xff1a;双亲委派机制 1. 例子2. 类加载器总结3. 类加载过程4. 双亲委派模型的执行流程&#xff1a;5. 双亲委派模型的好处 1. 例子 Java运行时环境有一个java.lang包&#xff0c;里面有一个ClassLoader类 我们自定义一个String类在java.lang包下&#xff0c;下面的…

WEB 3D技术 three.js 点光源

本文的话 我们来设置一下点光源 点光源其实最直观的就是可以做萤火虫 也可以做星光 点点的效果 我们可以直接在官网中搜索 Pointlight 大家可以在官网这里看一下 其实 SpotLight 聚关灯中的属性 Pointlight 点光源也有的 我们先编写代码如下 import ./style.css import * a…

MySQL之单表查询

素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 varchar(10) NO…

【Git】本地仓库管理远程库(GitHub)——clone(下载)、commit(添加到本地仓库)、push(提交到远程仓库)、pull(拉取)操作

目录 使用远程仓库的目的将本地仓库同步到git远程仓库 1.克隆远程仓库(clone)2.新建一个文件3.将工作区的文件添加到暂存区4.将暂存区的文件添加到本地仓库(commit)5.提交(同步)到远程仓库(push)6.远程库拉取到本地库(pull)7.团队协作开发和跨团队协作开发(开源项目) 使用远程…

PTA(浙大版《C语言程序设计(第3版)》题目集

PTA(浙大版《C语言程序设计&#xff08;第3版&#xff09;》题目集 学习C语言程序设计的PTA题目 目录 PTA(浙大版《C语言程序设计&#xff08;第3版&#xff09;》题目集PTA(浙大版《C语言程序设计&#xff08;第3版&#xff09;》题目集) 习题2-1 求整数均值 (10 分)输入格式:…

大型语言模型综述/总结 LLM A Survey of Large Language Models

A Survey of Large Language Model AbstractINTRODUCTIONOVERVIEW背景LLM的新兴能力LLM的关键技术GPT 系列模型的技术演进 大语言模型资源公开可用的模型检查点或 API常用语料库代码库资源 预训练数据收集架构 论文标题&#xff1a;A Survey of Large Language Model 论文地址&…

电子学会C/C++编程等级考试2023年09月(五级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 时间限制:1000 内存限制:65536 输入 包括多…

Linux的SSH远程管理和服务器之间的免密连接

目录 一、远程管理基础 1.ssh协议 2.ssh原理 3、使用ssh协议传输的命令 4.登录方法 二、免密连接 1.免密连接的原理 2.实战 一、远程管理基础 1.ssh协议 ssh协议是基于C/S机构的安全通道协议&#xff0c;通信数据进行加密处理&#xff0c;用于远程管理。 ssh的服务名…

Python文件读写与字符编码详解【第25篇—python基础知识】

文章目录 文件读写和字符编码在Python中的实现一、I/O操作概述二、文件读写实现原理与操作步骤1. 文件读写实现原理2. 文件读写操作步骤 三、文件打开模式四、Python文件操作步骤示例五、文件读取相关方法1. 读取指定长度的内容2. 读取文件中的一行内容3. 遍历打印一个文件中的…

Zookeeper使用详解

介绍 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服务、分布…

【搭建个人知识库-3】

搭建个人知识库-3 1 大模型开发范式1.1 RAG原理1.2 LangChain框架1.3 构建向量数据库1.4 构建知识库助手1.5 Web Demo部署 2 动手实践2.1 环境配置2.2 知识库搭建2.2.1 数据收集2.2.2 加载数据2.2.3 构建向量数据库 2.3 InternLM接入LangChain2.4 构建检索问答链1 加载向量数据…

鸿蒙应用开发学习:让page页面强制横屏

一、学习做了个适合横屏的页面但进入页面后是竖屏显示的 前几天在B站上跟着 黑马程序员的 HarmonyOS4.0开发应用教学视频学习了显式动画&#xff08;animateTo&#xff09;和属性动画&#xff08;animation&#xff09;功能&#xff0c;并参照教学视频的内容做了个小鱼动画。…