当前位置: 首页 > news >正文

Redis 7.x 系列【31】LUA 脚本

有道无术,术尚可求,有术无道,止于术。

本系列Redis 版本 7.2.5

源码地址:https://gitee.com/pearl-organization/study-redis-demo

文章目录

    • 1. 概述
    • 2. 常用命令
      • 2.1 EVAL
      • 2.2 SCRIPT LOAD
      • 2.3 EVALSHA
      • 2.4 SCRIPT FLUSH
      • 2.5 其他
    • 3. 脚本复制
    • 4. 案例演示
      • 4.1 限流
      • 4.2 分布式锁

1. 概述

官方文档

Lua 语言是一种小巧的、高效的、可嵌入的脚本编程语言,由巴西里约热内卢天主教大学的一个研究小组于 1993 年开发。设计目的是为了通过灵活嵌入应用程序中,为应用程序提供灵活的扩展和定制功能。

参考资料:

  • Lua 官网
  • 菜鸟教程

Redis 2.6 版本开始支持用户在服务器上传和执行 Lua 脚本,从而实现复杂的操作逻辑。脚本在 Redis 中是以字符串的形式传递给服务器的,然后服务器会执行这些脚本并返回结果。脚本在 Redis 中由内置的执行引擎执行。目前,仅支持一个脚本引擎,即 Lua 5.1 解释器。

Lua 脚本的优势:

  • 原子性:保证一个 Lua 脚本在执行期间是原子性的,即脚本执行期间不会被其他命令打断。在执行脚本期间,服务器的所有活动都会被阻塞,直到脚本运行结束。
  • 减少网络开销:可以将多个命令打包成一个 Lua 脚本执行,减少与 Redis 服务器的网络交互次数。
  • 复用性:可以将复杂的逻辑编写成 Lua 脚本,然后在多个地方重复使用。
  • 高效率:于脚本在服务器上执行,因此从脚本读取和写入数据非常高效。

注意事项:脚本被视为客户端应用程序的一部分,因此它们没有名称、版本或持久性。因此,如果脚本丢失(例如在服务器重新启动、故障切换到副本后等),所有脚本可能需要随时由应用程序重新加载

2. 常用命令

2.1 EVAL

在服务端执行 Lua 脚本。

语法格式:

EVAL script numkeys [key [key ...]] [arg [arg ...]]

参数说明:

  • scriptLua 编写的脚本源代码
  • numkeys :脚本中用到的 key 的数量
  • [key [key ...]]key 键名称列表,在脚本中可以使用 KEYS[] 进行占位,例如 EVAL 的第三个参数会被赋值给 KEYS[1] ,多个依次类推
  • [arg [arg ...]]:参数列表,在脚本中可以使用 ARGV[] 进行占位,例如 EVAL 的第四个参数会被赋值给 ARGV[1] ,多个依次类推

注意事项:

  • 禁止滥用 Lua EVAL ,例如,每次调用 EVAL 时生成不同的脚本。这些脚本将被添加到 Lua 解释器并缓存到服务端,随着时间的推移会消耗大量内存。
  • Redis 7.4 开始,使用 EVALEVAL_RO 加载的脚本将根据一定数量(按最近最少使用顺序)从 Redis 中删除。可以通过 INFO 命令查看被驱逐的脚本数量。

为了确保脚本在单机和集群环境中正确执行,还需要注意:

  • Lua 脚本的操作应该基于传递给脚本的参数进行,而不应该直接访问存储中的数据结构内容,例如哈希表、列表或集合。
  • 不支持动态键名访问或基于数据内容的键名计算,因此所有访问的键必须在执行脚本时已经确定。这些输入键的名称作为 KEYS 全局运行时变量提供给 Lua 脚本使用。

简单示例:

localhost:0>EVAL "return 'Hello, scripting!'" 0
"Hello, scripting!"

示例说明:

  • return 'Hello, scripting!':使用双引号包含的脚本源代码,返回一个字符串
  • 0:没有使用到键

包含参数示例:

localhost:0>EVAL "return ARGV[1]" 0 Hello
"Hello"

示例说明:

  • 0:没有使用到键
  • Hello:将 Hello 传递给 ARGV[1]

包含键、参数示例:

redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg3
1) "key1"
2) "key2"
3) "arg1"
4) "arg2"
5) "arg3"

示例说明:

  • 2:包含两个键
  • key1:将 Hello 传递给 KEYS[1],按照位置顺序依次类推
  • arg1:将 arg1 传递给 ARGV[1],按照位置顺序依次类推

可以通过 redis.call()redis.pcall()Lua 脚本中调用 Redis 命令,区别在于处理运行时错误(例如语法错误)的方式:

  • call():如果发生错误,错误会直接返回给执行它的客户端
  • pcall():遇到的错误会返回到脚本的执行环境

示例:

EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
OK

2.2 SCRIPT LOAD

每次调用 EVAL 命令时,请求中都会包括脚本的源代码,重复调用来执行相同的脚本集会浪费网络带宽,并且在 Redis 中也会产生一些额外开销,因此 Redis 提供了脚本的缓存机制。

使用 SCRIPT LOAD 可以将 Lua 脚本加载到 Redis 服务器,服务器不会执行脚本,而是仅编译并加载到服务器的缓存中。加载后返回一个 SHA1 摘要,唯一标识了它在缓存中的位置,该摘要可以用于执行已加载的脚本。

语法格式:

SCRIPT LOAD script

注意事项:

  • 脚本缓存始终是易失性的,它不被视为数据库的一部分,也不会持久化存储。当服务器重新启动、在故障转移时从副本切换为主服务器时,或者通过调用 SCRIPT FLUSH 命令时,缓存可能会被清空。
  • 应用程序应首先用 SCRIPT LOAD 加载脚本,然后再次调用 EVALSHA 运行缓存的脚本。大多数 Redis 客户端已经提供了自动执行此过程的 API

示例:

redis> SCRIPT LOAD "return 'Immabe a cached script'"
"c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f"
redis> EVALSHA c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f 0
"Immabe a cached script

2.3 EVALSHA

用于执行已加载的 Lua 脚本。

语法格式:

EVALSHA <sha1> <numkeys> <key> [key ...] <arg> [arg ...]

参数说明:

  • <sha1>:之前已加载缓存的 Lua 脚本的 SHA1 值。

示例:

127.0.0.1:6379> SCRIPT LOAD "local key = KEYS[1]\nlocal value = ARGV[1]\n\nredis.call('SET', key, value)"
"5b405e1d1f5c91b27e7e2b091380a848d38a99d6"
127.0.0.1:6379> EVALSHA 5b405e1d1f5c91b27e7e2b091380a848d38a99d6 1 mykey "myvalue"
OK

注意事项:

  • SHA1 对应的脚本不存在时,会报错
  • 在使用管道时,尽量不要使用 EVALSHA ,管道请求中的命令按发送顺序执行,但其他客户端的命令可能会在这些命令之间交错执行。因此,可能会从管道请求中返回NOSCRIPT错误,但无法进行处理。因此,在管道中应当使用普通的 EVAL 或带参数的 EVAL

2.4 SCRIPT FLUSH

清空 Lua 脚本缓存。默认情况下,SCRIPT FLUSH 命令会同步清空缓存。从 Redis 6.2 开始,设置 lazyfree-lazy-user-flush 配置指令为 “yes” 将改变默认的清空模式为异步。

语法格式:

SCRIPT FLUSH [ASYNC | SYNC]

参数说明:

  • ASYNC:异步清空缓存
  • SYNC:同步清空缓存

注意事项:

  • 运行命令将完全清空脚本缓存,删除到目前为止执行的所有脚本。
  • 在正常操作期间,脚本应该在缓存中无限期地保留。

示例:

localhost:0>SCRIPT FLUSH
"OK"

2.5 其他

其他脚本相关的命令:

  • EVAL_ROEVAL 命令的只读变体,不能执行修改数据的命令。
  • EVALSHA_ROEVALSHA 命令的只读变体,不能执行修改数据的命令。
  • SCRIPT DEBUG:控制内置的 Redis Lua 脚本调试器。
  • SCRIPT EXISTS:判断脚本已存在于缓存中,一个或多个 SHA1 摘要作为参数。返回 1 表示存在, 0 不存在。
  • SCRIPT KILL:中断长时间运行脚本(即慢脚本)的唯一方式,除非关闭服务器。脚本在执行时间超过配置的最大执行时间阈值后被视为慢脚本。只能用于在执行期间未修改数据集的脚本(因为停止只读脚本不会违反脚本引擎的原子性保证)。

3. 脚本复制

集群部署环境下,至少有三个主节点,每个主节点有一个或多个从节点,主从之间使用完全复制保持数据一致性。由于脚本可以修改数据,Redis 确保脚本执行的所有写操作也会被发送到从节点以保持一致性。

脚本复制有以下两种方式:

  • 逐字复制:主节点将脚本的源代码发送到副本,副本然后执行脚本并应用写入效果。
  • 效果复制:只复制脚本的数据修改命令,副本随后运行这些命令而不执行任何脚本。

逐字复制模式意味着副本会重新执行主节点已完成的工作,这是一种浪费。更重要的是,它还要求所有写入脚本都是确定性的。效果复制模式虽然在网络流量方面可能更为冗长,但这种复制模式是确定性的,因此不需要特别考虑其他情况。

直到 Redis 3.2 版本之前,逐字脚本复制是唯一支持的模式,在 Redis 3.2 中添加了效果复制。在 Redis 5.0 中,效果复制成为默认模式,截至 Redis 7.0 ,不再支持逐字复制。

在效果复制模式下,当 Lua 脚本执行时, Redis 会收集 Lua 脚本引擎实际修改数据集的所有命令。当脚本执行结束时,脚本生成的命令序列会被封装成一个 MULTI/EXEC 事务,并发送到副本和 AOF

效果复制的优势:

  • 当脚本计算速度较慢,可以由少数写入命令替换时,重新在副本或重新加载 AOF上计算脚本是一种浪费。在这种情况下,仅复制脚本的效果要好得多。
  • 解除了非确定性函数的限制。例如,您可以在脚本中任意使用 TIMESRANDMEMBER 命令。
  • Lua 伪随机数生成器在每次调用时都是随机种子。

4. 案例演示

Redis 命令的执行是单线程的,Lua 脚本在执行期间是原子性的,并且可以同时执行多个命令。特别适用于多线程环境下,需要保证多个复杂操作的原子性的场景。

4.1 限流

演示需求: 基于固定时间窗口进行 IP 限流, 同一 IP 在一分钟内,只允许访问固定的次数。

resources 目录下添加限流脚本文件:

local ipKey = KEYS[1]; -- IP地址
local rate = tonumber(ARGV[1]); -- 允许的请求次数
local requestCount = redis.call('incr', ipKey); -- 每次请求 + 1
if (requestCount == 1) then -- 第一次请求redis.call('expire', ipKey, 60); -- 设置过期时间(60S)return true ; -- 返回是否允许访问
else -- 不是第一次请求if (requestCount > rate) then -- 如果当前请求次数大于允许的请求次数return false ;end
end

使用 Lettuce 客户端执行脚本:

    public static void main(String[] args) {// 创建客户端RedisClient redisClient = RedisClient.create("redis://:123456@127.0.0.1:6379/0");// 获取连接try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {// 执行命令RedisCommands<String, String> sync = connection.sync();// 获取脚本流byte[] lua = getResourceAsByteArray("limit.lua"); // 执行脚本boolean eval = sync.eval(lua, ScriptOutputType.BOOLEAN, new String[]{"127.0.0.1"}, "1");// 结果判断if (!eval) {System.out.println("当前访问过于频繁,请稍后重试");} else {System.out.println("允许访问");}} catch (Exception e) {throw new RuntimeException(e);} finally {redisClient.shutdown();}}public static byte[] getResourceAsByteArray(String resourceName) throws IOException {// 使用ClassLoader获取资源作为输入流try (InputStream inputStream = LuaTest.class.getClassLoader().getResourceAsStream(resourceName)) {if (inputStream == null) {return null;}// 将输入流转换为字节数组ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, length);}return outputStream.toByteArray();}}

4.2 分布式锁

演示需求: 商品秒杀防止超卖,使用 Redis +Lua 实现分布式锁(生产环境请使用成熟的框架)。

获取锁的命令:

SET key value NX EX expire_time

简单的实现原理:

  • 使用 SET NX... 命令设置值,设置成功表示获取到的锁,反之未获取(直接返回失败或循环重试),并设置一个过期时间(避免死锁)
  • 获取到锁后,执行业务逻辑
  • 执行完成后释放锁

resources 目录下添加尝试获取锁脚本文件 tryLock.lua

local lockKey = KEYS[1] -- 锁的key
local lockValue = ARGV[1]   -- 锁的值
local lockExpireTime = tonumber(ARGV[2])  -- 锁的过期时间(秒)
local acquiredLock = redis.call('SET', lockKey, lockValue, 'NX', 'EX', lockExpireTime) -- 获取锁
if acquiredLock thenreturn true   -- 获取锁成功
elsereturn false -- 获取锁失败
end

添加删除锁脚本文件 unlock.lua

local lockKey = KEYS[1] -- 锁的key
redis.call('DEL', lockKey) -- 删除锁

创建工具类封装相关分布式锁逻辑:

public class RedisLockUtils {/*** 尝试获取锁** @param sync   连接* @param key    锁的 Key* @param value  锁的值* @param second 过期时间* @return 是否获取到锁* @throws IOException*/public static boolean tryLock(RedisCommands<String, String> sync, String key, String value, String second) throws IOException {byte[] lua = RedisLockUtils.getResourceAsByteArray("tryLock.lua"); // 获取脚本流return sync.eval(lua, ScriptOutputType.BOOLEAN, new String[]{key}, value, second);      // 执行脚本}/*** 删除锁** @param sync 连接* @param key  锁的 Key* @return 是否获取到锁* @throws IOException*/public static void unlock(RedisCommands<String, String> sync, String key) throws IOException {byte[] lua = RedisLockUtils.getResourceAsByteArray("unlock.lua");boolean eval = sync.eval(lua, ScriptOutputType.BOOLEAN, new String[]{key});}public static byte[] getResourceAsByteArray(String resourceName) throws IOException {// 使用ClassLoader获取资源作为输入流try (InputStream inputStream = LuaLimitTest.class.getClassLoader().getResourceAsStream(resourceName)) {if (inputStream == null) {return null;}// 将输入流转换为字节数组ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, length);}return outputStream.toByteArray();}}
}

模拟秒杀,简单测试:

public class LuaLockTest {private static Integer stockCount = 100; // 商品库存数量private static String goodsId = "899632563356632489"; // 商品库存数量public static void main(String[] args) {// 创建客户端RedisClient redisClient = RedisClient.create("redis://:123456@127.0.0.1:6379/0");// 获取连接try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {// 秒杀逻辑try {// 获取到锁if (RedisLockUtils.tryLock(connection.sync(), goodsId, "123456", "10")) {// 减库存if (stockCount > 0) {stockCount = stockCount - 1;System.out.println("减库存成功,剩余库存:" + stockCount);} else {System.out.println("库存不足");}} else {System.out.println("库存不足");}} finally {// 释放锁RedisLockUtils.unlock(connection.sync(), goodsId);}} catch (Exception e) {throw new RuntimeException(e);} finally {redisClient.shutdown();}}
}

相关文章:

Redis 7.x 系列【31】LUA 脚本

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 常用命令2.1 EVAL2.2 SCRIPT LOAD2.3 EVALSHA2.4 SCRIPT FLUSH2.5 其他 3. …...

mysql中You can’t specify target table for update in FROM clause错误

mysql中You can’t specify target table for update in FROM clause错误 You cannot update a table and select directly from the same table in a subquery. mysql官网中有这句话&#xff0c;我们不能在一个语句中先在子查询中从某张表查出一些值&#xff0c;再update这张表…...

Linux Vim最全面的教程

Vim 是一个非常强大的文本编辑器&#xff0c;它在 Linux 环境中尤其受欢迎。Vim 支持高度定制&#xff0c;并且拥有丰富的功能&#xff0c;包括多级撤销、宏、脚本语言支持等。下面是关于 Vim 的一个较为全面的教程。 Vim 的启动 要启动 Vim&#xff0c;你可以在终端中输入 v…...

setsockopt选项对tcp速度

GPT-4 (OpenAI) 每个setsockopt调用都涉及到一个套接字描述符&#xff0c;一个指定网络层的常数&#xff08;如IPPROTO_IP, IPPROTO_TCP, IPPROTO_IPV6, SOL_SOCKET等&#xff09;&#xff0c;一个指定需配置的选项的常数&#xff0c;一个指向配置值的指针&#xff0c;以及那个…...

HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 多选题序号3

基础认证题库请移步&#xff1a;HarmonyOS应用开发者基础认证题库 注&#xff1a;有读者反馈&#xff0c;题库的代码块比较多&#xff0c;打开文章时会卡死。所以笔者将题库拆分&#xff0c;单选题20个为一组&#xff0c;多选题10个为一组&#xff0c;题库目录如下&#xff0c;…...

bool数组的理解和应用[C++]

文章目录 bool数组的用法bool数组的定义声明bool数组的初始化访问和修改数组元素遍历数组 运用bool数组简单代码 在今天做题中发现了bool类不仅能用于函数类型还能用于数组类型&#xff0c;好奇查了查发现bool还有很多用处&#xff1a;基本变量&#xff0c;在枚举类型中会用到&…...

JavaScript模拟滑动手势

双击回到顶部 左滑动 右滑动 代码展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Gesture…...

Text Control 控件教程:使用 .NET C# 中的二维码和条形码增强文档

QR 码和条形码非常适合为文档和 PDF 文件增加价值&#xff0c;因为它们提供轻松的信息访问、验证信息、跟踪项目和提高交互性。条形码可以弥补纸质或数字人类可读文档与网络门户或网络应用程序中的数字信息之间的差距。大多数用户都熟悉 QR 码和条形码&#xff0c;它们在许多过…...

最新爆火的开源AI项目 | LivePortrait 本地安装教程

LivePortrait 本地部署教程&#xff0c;强大且开源的可控人像AI视频生成 1&#xff0c;准备工作&#xff0c;本地下载代码并准备环境&#xff0c;运行命令前需安装git 以下操作不要安装在C盘和容量较小的硬盘&#xff0c;可以找个大点的硬盘装哟 2&#xff0c;需要安装FFmp…...

揭秘Django与Neo4j:构建智能知识图谱的终极指南

揭秘Django与Neo4j:构建智能知识图谱的终极指南 前言 图是一种用于对象之间的成对关系进行建模的数学结构。 它由两个主要元素组成:节点和关系。 节点:节点可以看作是传统数据库中的记录。每个节点代表一个对象或实体,例如一个人或一个地方。节点按标签分类,这有助于根…...

项目一缓存商品

文章目录 概要整体架构流程技术细节小结 概要 因为商品是经常被浏览的,所以数据库的访问量就问大大增加,造成负载过大影响性能,所以我们需要把商品缓存到redis当中,因为redis是存在内存中的,所以效率会比MySQL的快. 整体架构流程 技术细节 我们在缓存时需要保持数据的一致性所…...

SEO与数据中心代理IP的结合能带来哪些便利?

本文将探讨将SEO与数据中心代理IP结合所带来的好处&#xff0c;以及如何利用这种组合来提升网站在搜索引擎中的排名和可见性。 1. 数据中心代理IP的作用和优势 数据中心代理IP指的是由数据中心提供的IP地址&#xff0c;用于隐藏真实服务器的位置和身份。与其他类型的代理IP相…...

《昇思25天学习打卡营第6天|ResNet50图像分类》

写在前面 从本次开始&#xff0c;接触一些上层应用。 本次通过经典的模型&#xff0c;开始本次任务。这里开始学习resnet50网络模型&#xff0c;应该也会有resnet18&#xff0c;估计18的模型速度会更快一些。 resnet 通过对论文的结论进行展示&#xff0c;说明了模型的功能&…...

Activiti 6 兼容openGauss数据库bytes类型不匹配

当前有个项目需要做国产调研&#xff0c;需要适配高斯数据库&#xff0c;项目启动的时候&#xff0c;提示column "bytes_" is type bytea but expression is of type blob byte_字段是act_ge_bytearray表的&#xff0c;openGauss里的类型是bytea&#xff0c;类型是匹…...

缓存技术:提升性能与效率的利器

在当今数字化时代&#xff0c;软件应用的性能与响应速度成为了衡量其成功与否的重要标准之一。随着数据量的爆炸性增长和用户需求的日益多样化&#xff0c;如何高效地处理这些数据并快速响应用户请求成为了软件开发中亟待解决的问题。缓存技术&#xff0c;作为提升系统性能、优…...

LeetCode 637, 67, 399

文章目录 637. 二叉树的层平均值题目链接标签思路代码 67. 二进制求和题目链接标签思路代码 399. 除法求值题目链接标签思路导入value 属性find() 方法union() 方法query() 方法 代码 637. 二叉树的层平均值 题目链接 637. 二叉树的层平均值 标签 树 深度优先搜索 广度优先…...

如何压缩视频大小不改变画质?这5个视频压缩免费软件超好用!

如何压缩视频大小不改变画质&#xff1f;随着生活的水平逐步提高&#xff0c;视频流媒体服务越来越受欢迎。提供简短而引人注目的视频来展示您的产品或服务已成为一种出色的营销手段。然而&#xff0c;当您要准备导出最终视频时&#xff0c;可能会面临一个常见问题&#xff1a;…...

深入理解 Java 虚拟机第三版(周志明)

这次社招选的这本作为 JVM 资料查阅&#xff0c;记录一些重点 1. 虚拟机历史 Sun Classic VM &#xff1a;已退休 HotSpot VM&#xff1a;主流虚拟机&#xff0c;热点代码探测技术 Mobile / Embedded VM &#xff1a;移动端、嵌入式使用的虚拟机 2.2 运行时数据区域 程序计…...

算法 定长按组翻转链表

一、题目 已知一个链表的头部head&#xff0c;每k个结点为一组&#xff0c;按组翻转。要求返回翻转后的头部 k是一个正整数&#xff0c;它的值小于等于链表长度。如果节点总数不是k的整数倍&#xff0c;则剩余的结点保留原来的顺序。示例如下&#xff1a; &#xff08;要求不…...

安装nfs和rpcbind设置linux服务器共享磁盘

1、安装nfs和rpcbind 1.1 检查服务器是否安装nfs和rpcbind&#xff0c;执行下命令&#xff0c;检查服务器是否安装过。 rpm -qa|grep nfs rpm -qa|grep rpcbind 说明服务器以安装了&#xff0c;如果没有就需要自己安装 2、安装nfs和rpcbind 将rpm安装包&#xff1a; libtirpc-…...

物联网在电力行业的应用

作者主页: 知孤云出岫 这里写目录标题 作者主页:物联网在电力行业的应用简介主要应用领域代码案例分析1. 智能电表数据采集和分析2. 设备监控和预测性维护3. 能耗管理和优化4. 电力负载预测5. 分布式能源管理6. 电动汽车充电管理7. 电网安全与故障检测 物联网在电力行业的应用…...

Java 代码规范if嵌套

在Java编程中&#xff0c;过度的if嵌套会使代码难以阅读和维护。为了遵循良好的代码规范&#xff0c;我们应尽量减少嵌套的深度。这通常可以通过重新组织代码或使用其他结构&#xff08;如switch语句&#xff0c;或者将逻辑封装到单独的方法中&#xff09;来实现。 以下是一个…...

ASPICE如何确保汽车软件产品质量的稳固基石

ASPICE通过一系列的方法和原则来保障汽车软件产品的质量&#xff0c;以下是其保障产品质量的几个关键方面&#xff1a; 制定明确的质量方针和目标&#xff1a; ASPICE要求组织制定明确的质量方针和目标&#xff0c;这些方针和目标与客户需求和预期相一致。 开发团队需要定义软…...

【深度学习】yolov8-seg分割训练,拼接图的分割复原

文章目录 项目背景造数据训练 项目背景 在日常开发中&#xff0c;经常会遇到一些图片是由多个图片拼接来的&#xff0c;如下图就是三个图片横向拼接来的。是否可以利用yolov8-seg模型来识别出这张图片的三张子图区域呢&#xff0c;这是文本要做的事情。 造数据 假设拼接方式有…...

Python升级打怪—Django入门

目录 一、Django简介 二、安装Django 三、创建Dajngo项目 (一) 创建项目 (二) 项目结构介绍 (三) 运行项目 (四) 结果 一、Django简介 Django是一个高级Python web框架&#xff0c;鼓励快速开发和干净、实用的设计。由经验丰富的开发人员构建&#xff0c;它解决了web开…...

leetcode面试题17.最大子矩阵

sooooooo long没刷题了&#xff0c;汗颜 题目链接&#xff1a;leetcode面试题17 1.题目 给定一个正整数、负整数和 0 组成的 N M 矩阵&#xff0c;编写代码找出元素总和最大的子矩阵。 返回一个数组 [r1, c1, r2, c2]&#xff0c;其中 r1, c1 分别代表子矩阵左上角的行号和…...

计算机网络:构建联结的基础

目录 1. 网络拓扑结构 1.1 星型拓扑 1.2 环型拓扑 1.3 总线型拓扑 1.4 网状拓扑 2. 传输介质 2.1 双绞线 2.2 同轴电缆 2.3 光纤 2.4 无线电波 3. 协议栈模型 3.1 OSI模型 3.2 TCP/IP模型 4. 网络设备 4.1 交换机 4.2 路由器 4.3 网关 4.4 防火墙 5. IP地址…...

node和npm安装;electron、 electron-builder安装

1、node和npm安装 参考&#xff1a; https://blog.csdn.net/sw150811426/article/details/137147783 下载&#xff1a; https://nodejs.org/dist/v20.15.1/ 安装&#xff1a; 点击下载msi直接运行安装 安装完直接cmd打开可以&#xff0c;默认安装就已经添加了环境变量&…...

操作系统概念(黑皮书)阅读笔记

操作系统概念&#xff08;黑皮书&#xff09;阅读笔记 进程和内存管理部分章节 导论&#xff1a; 操作系统类似于政府&#xff0c;其本身不能实现任何有用功能&#xff0c;而是提供一个方便其他程序执行有用工作的环境 ​ 个人理解&#xff1a;os是government的作用&#xff0…...

matlab gui下的tcp client客户端编程框架

GUI界面 函数外定义全局变量 %全局变量 global TcpClient; %matlab作为tcpip客户端 建立连接 在“连接”按钮的回调函数下添加以下代码&#xff1a; global TcpClient;%全局变量 TcpClient tcpip(‘192.168.1.10’, 7, ‘NetworkRole’,‘client’); %连接到服务器地址和端…...

Matplotlib : Python 的绘图库

Matplotlib 是一个 Python 的绘图库&#xff0c;广泛用于生成各种静态、动态、交互式的图表。它基于 NumPy&#xff0c;一个用于科学计算的 Python 库。Matplotlib 可以用于生成出版质量级别的图表&#xff0c;并且提供了丰富的定制选项&#xff0c;以适应不同用户的需求。以下…...

数据编织 VS 数据仓库 VS 数据湖

目录 1. 什么是数据编织?2. 数据编织的工作原理3. 代码示例4. 数据编织的优势5. 应用场景6. 数据编织 vs 数据仓库6.1 数据存储方式6.2 数据更新和实时性6.3 灵活性和可扩展性6.4 查询性能6.5 数据治理和一致性6.6 适用场景6.7 代码示例比较 7. 数据编织 vs 数据湖7.1 数据存储…...

CSS(十一)——CSS分组和嵌套,尺寸(Dimension)

CSS 分组 和 嵌套 选择器 分组选择器 举个例子&#xff0c;多个标签有同一个样式&#xff0c;就可以不一个一个分开写&#xff0c;使用分组选择器 比如&#xff1a; h1 {color:green; } h2 {color:green; } p {color:green; } 就可以写为&#xff1a; h1,h2,p {color…...

必备神器!三款优秀远程控制电脑软件推荐

嘿&#xff0c;各位职场小伙伴们&#xff0c;今儿个咱们来聊聊个挺实用又带点“科技范儿”的话题——电脑远程控制那点事儿。作为刚踏入职场不久的新人&#xff0c;我深刻体会到&#xff0c;在这信息爆炸的时代&#xff0c;掌握几招远程操作的技能&#xff0c;简直就是给自个儿…...

关于正运动学解机器人手臂算法

机器人正运动学是机器人学的一个分支&#xff0c;研究机器人的运动和位置之间的关系。它通过解析机器人的结构和关节参数&#xff0c;以及给定的关节角度&#xff0c;来计算机器人的末端执行器的位置和姿态。 机器人正运动学算法通常使用DH&#xff08;Denavit-Hartenberg&…...

MySQL 约束 (constraint)

文章目录 约束&#xff08;constraint)列级约束和表级约束给约束起名字&#xff08;constraint)非空约束&#xff08;no null)检查约束&#xff08;check)唯一性约束 (unique)主键约束 (primary key)主键分类单一主键复合主键主键自增 &#xff08;auto_increment) 外键约束外什…...

用python程序发送文件(python实例二十六)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.文件上传 3.1 代码构思 3.2 服务端代码 3.3 客户端代码 3.4 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具…...

最新源支付系统源码 V7版全开源 免授权 附搭建教程

本文来自&#xff1a;最新源支付系统源码 V7版全开源 免授权 附搭建教程 - 源码1688 简介&#xff1a; 最新源支付系统源码_V7版全开源_免授权_附详细搭建教程_站长亲测 YPay是专为个人站长打造的聚合免签系统&#xff0c;拥有卓越的性能和丰富的功能。它采用全新轻量化的界面…...

HTML:lang属性作用

lang作用 用法常见语言代码优点示例结构效果说明分析HTML 基础结构导航栏内容部分总结 扩展 用法 HTML 文档级别: 在 <html> 标签上使用 lang 属性&#xff0c;指定整个文档的语言。 <!DOCTYPE html> <html lang"en"> <head><meta charse…...

Android SurfaceFlinger——纹理的绘制流程(二十八)

在系统开机动画的播放流程中,会从给定的资源文件中加载纹理数据并初始化一个 OpenGL 纹理对象,这里我们就来解析软件模拟纹理的绘制流程。 一、纹理概述 在 Android 的 SurfaceFlinger 系统组件中,纹理(Texture)是一个核心概念,特别是在涉及到图形渲染和显示的过程中。 …...

深入解析Memcached:C#中的应用与实战案例

目录 Memcached简介Memcached的特点Memcached的工作原理Memcached的应用场景Memcached的安装和配置Memcached与C#的集成 引入依赖配置Memcached客户端C#代码示例 存储数据读取数据删除数据深入解析Memcached 数据存储和过期策略分布式架构性能优化实战案例 缓存数据库查询结果实…...

keyring 库

目录 安装 keyring 基本用法 1. 设置密码 2. 获取密码 3. 删除密码 4. 返回当前使用的默认密钥环 5. 列出所有密码 支持的后端 keyring 是一个 Python 库&#xff0c;用于将敏感信息&#xff08;如密码&#xff09;安全地存储在操作系统的密码管理器中。它支持多种平台…...

[css3] 如何设置边框颜色渐变

div {border: 4px solid;border-image: linear-gradient(to right, #8f41e9, #578aef) 1; }参考&#xff1a; 5种CSS实现渐变色边框&#xff08;Gradient borders方法的汇总...

Redux +Toolkit 工具包快速入门

您将学到什么 如何设置并使用 Redux Toolkit 和 React-Redux 先决条件 熟悉ES6 语法和功能了解 React 术语&#xff1a;JSX、State、Function Components 、 Props和Hooks理解Redux 术语和概念 1、基本使用 1.1、安装 Redux Toolkit 和 React- Redux 将 Redux Toolkit 和 Rea…...

【Python数据增强】图像数据集扩充

前言&#xff1a;该脚本用于图像数据增强&#xff0c;特别是目标检测任务中的图像和标签数据增强。通过应用一系列数据增强技术&#xff08;如旋转、平移、裁剪、加噪声、改变亮度、cutout、翻转等&#xff09;&#xff0c;生成多样化的图像数据集&#xff0c;以提高目标检测模…...

实时同步:使用 Canal 和 Kafka 解决 MySQL 与缓存的数据一致性问题

目录 1. 准备工作 2. 将需要缓存的数据存储 Redis 3. 监听 canal 存储在 Kafka Topic 中数据 1. 准备工作 1. 开启并配置MySQL的 BinLog&#xff08;MySQL 8.0 默认开启&#xff09; 修改配置&#xff1a;C:\ProgramData\MySQL\MySQL Server 8.0\my.ini log-bin"HELO…...

WINUI——Microsoft.UI.Xaml.Markup.XamlParseException:“无法找到与此错误代码关联的文本。

开发环境 VS2022 .net core6 问题现象 在Canvas内的子控件要绑定Canvas的兄弟控件的一个属性&#xff0c;在运行时出现了下述报错。 可能原因 在 WinUI&#xff08;特别是用于 UWP 或 Windows App SDK 的版本&#xff09;中&#xff0c;如果你尝试在 XAML 中将 Canvas 内的…...

C语言 | Leetcode C语言题解之第283题移动零

题目&#xff1a; 题解&#xff1a; void swap(int *a, int *b) {int t *a;*a *b, *b t; }void moveZeroes(int *nums, int numsSize) {int left 0, right 0;while (right < numsSize) {if (nums[right]) {swap(nums left, nums right);left;}right;} }...

WPF项目实战视频《二》(主要为prism框架)

14.prism框架知识&#xff08;1&#xff09; 使用在多个平台的MVVM框架 新建WPF项目prismDemo 项目中&#xff1a;工具-NuGet包管理&#xff1a;安装Prism.DryIoc框架 在git中能看Prism的结构和源代码&#xff1a;git链接地址 例如&#xff1a;Prism/src/Wpf/Prism.DryIoc.Wpf…...

【微信小程序实战教程】之微信小程序 WXS 语法详解

WXS语法 WXS是微信小程序的一套脚本语言&#xff0c;其特性包括&#xff1a;模块、变量、注释、运算符、语句、数据类型、基础类库等。在本章我们主要介绍WXS语言的特性与基本用法&#xff0c;以及 WXS 与 JavaScript 之间的不同之处。 1 WXS介绍 在微信小程序中&#xff0c…...