使用真实 Elasticsearch 进行高级集成测试
作者:来自 Elastic Piotr Przybyl
掌握高级 Elasticsearch 集成测试:更快、更智能、更优化。
在上一篇关于集成测试的文章中,我们介绍了如何通过改变数据初始化策略来缩短依赖于真实 Elasticsearch 的集成测试的执行时间。在本期中,我们将进一步缩短测试套件的持续时间,这次我们将通过将高级技术应用于运行 Elasticsearch 的 Docker 容器和 Elasticsearch 本身。
请注意,下面描述的技术通常可以精挑细选:你可以选择最适合你特定情况的技术。
这里有“龙”:权衡取舍
在我们深入探讨各种性能优化方法之前,必须明白一个道理:并非所有优化都应该无条件应用。尽管优化通常能带来提升,但它们也可能让整体设置变得更难理解,尤其是对于不熟悉的人来说。换句话说,在接下来的章节中,我们不会修改测试本身,而是重新设计其周围的 “基础架构代码”。这些改动可能会让代码对经验不足的团队成员来说更加晦涩。文中介绍的技术并非高深莫测,但在使用时仍需谨慎,并且有一定经验会更好。
快照
当我们停止演示代码时,我们仍在使用每个测试的数据初始化 Elasticsearch。这种方法有一些优势,特别是如果我们的数据集在测试用例之间有所不同,例如,我们有时会索引略有不同的文档。但是,如果我们所有的测试用例都可以依赖相同的数据集,我们可以使用快照和恢复方法。
了解快照和恢复在 Elasticsearch 中的工作方式很有帮助,官方文档对此进行了解释。
在我们的方法中,我们不是通过 CLI 或 DevOps 方法处理这个问题,而是将其集成到测试周围的设置代码中。这确保了在开发人员机器以及 CI/CD 中顺利执行测试。
这个想法很简单:我们不是删除索引并在每次测试之前从头开始重新创建它们,而是:
- 在容器的本地文件系统中创建快照(如果它尚不存在,因为这在以后会变得必要)。
- 在每次测试之前恢复快照。
准备快照位置
需要注意的一件重要事情 —— 这使得 Elasticsearch 与许多关系数据库不同 —— 在发送创建快照的请求之前,我们首先需要注册一个可以存储快照的位置,即所谓的存储库。有许多可用的存储选项(这对于云部署非常方便);在我们的例子中,将它们保存在容器内的本地目录中就足够了。
注意:
此处使用的 /tmp/... 位置仅适用于易变集成测试,切勿在生产环境中使用。在生产环境中,请始终将快照存储在安全可靠的位置以进行备份。
为了避免将备份存储在不安全的位置,我们首先将其添加到我们的测试中:
static final String REPO_LOCATION = "/tmp/bad_backup_location";
接下来,我们配置 ElasticsearchContainer 以确保它可以使用此位置作为备份位置:
static ElasticsearchContainer elasticsearch =new ElasticsearchContainer(ELASTICSEARCH_IMAGE)// other instructions.withEnv("path.repo", REPO_LOCATION);
更改设置
现在我们准备将以下逻辑附加到我们的 @BeforeAll 方法中:
if (!snapshotExists()) {setupDataInContainer();createSnapshotInContainer();
}
我们的 @BeforeEach 方法应该以以下内容开头:
restoreSnapshot();
可以通过验证 REPO_LOCATION 目录是否存在并包含一些文件来检查快照是否存在:
static boolean snapshotExists() throws IOException, InterruptedException {ExecResult execResult = elasticsearch.execInContainer("sh", "-c", "[ -d \"" + REPO_LOCATION + "\" ] && [ \"$(ls -A " + REPO_LOCATION + ")\" ]");return execResult.getExitCode() == 0;
}
setupDataInContainer() 方法略有变化:它不再在 @BeforeEach 中调用(我们在需要时按需执行它),并且可以删除 DELETE books 请求(因为不再需要它)。
要创建快照,我们首先需要注册一个快照位置,然后在那里存储任意数量的快照(尽管我们只保留一个,因为测试不需要更多):
static void createSnapshotInContainer() throws IOException, InterruptedException {// Register REPO_LOCATION for backupsExecResult result = elasticsearch.execInContainer("curl", "https://localhost:9200/_snapshot/init_backup", "-u", "elastic:changeme","--cacert", "/usr/share/elasticsearch/config/certs/http_ca.crt","-H", "Content-Type: application/json","-X", "PUT","-d", """{"type":"fs","settings":{"location":"%s"}}""".formatted(REPO_LOCATION));assert result.getExitCode() == 0 && result.getStdout().contains("\"acknowledged\":true");// Create the snapshot and wait for completionresult = elasticsearch.execInContainer("curl", "https://localhost:9200/_snapshot/init_backup/snapshot_1?wait_for_completion=true", "-u", "elastic:changeme","--cacert", "/usr/share/elasticsearch/config/certs/http_ca.crt","-H", "Content-Type: application/json","-X", "PUT","-d", """{"indices": ["books"]}""");assert result.getExitCode() == 0;
}
一旦创建快照,我们可以在每次测试之前恢复它,如下所示:
static void restoreSnapshot() {Container.ExecResult execResult;try {execResult = elasticsearch.execInContainer("/bin/sh", "-c", """curl --cacert /usr/share/elasticsearch/config/certs/http_ca.crt -s -u elastic:changeme -X DELETE "https://localhost:9200/books" \&& \curl --cacert /usr/share/elasticsearch/config/certs/http_ca.crt -s -u elastic:changeme -X POST https://localhost:9200/_snapshot/init_backup/snapshot_1/_restore?wait_for_completion=true""");} catch (Exception e) {throw new RuntimeException(e);}if (execResult.getExitCode() != 0) {throw new RuntimeException("Error when restoring backup: [%s] [%s]".formatted(execResult.getStdout(), execResult.getStderr()));}
}
请注意以下几点:
- 在恢复索引之前,索引不能存在,因此我们必须先将其删除。
- 如果你需要删除多个索引,则可以在单个 curl 调用中执行此操作,例如 “https://localhost:9200/indexA,indexB”。
- 要在容器中链接多个命令,你无需将它们包装在单独的 execInContainer 调用中;运行简单的脚本可以提高可读性(并减少一些网络往返)。
在示例项目中,此技术将我的构建时间缩短至 26 秒。虽然乍一看这似乎不是一个显着的收益,但该方法是一种通用技术,可以在切换到 _bulk 摄取(在上一篇文章中讨论)之前甚至代替它应用。换句话说,你可以以任何方式在 @BeforeAll 中为测试准备数据,然后对其进行快照以在 @BeforeEach 中使用。如果你想最大限度地提高效率,甚至可以使用 elasticsearch.copyFileFromContainer(...) 将快照复制回测试机器,使其作为一种缓存形式,仅在你需要更新数据集(例如,测试新功能)时才会清除。有关完整示例,请查看标签 snapshots。
将数据保存在 RAM 中
有时,我们的测试用例明显包含大量数据,这可能会对性能产生负面影响,尤其是在底层存储速度较慢的情况下。如果你的测试需要读取和写入大量数据,而 SSD 甚至硬盘速度非常慢,你可以指示容器将数据保存在 RAM 中 - 前提是你有足够的可用内存。
这本质上是一行代码,需要在容器定义中添加 .withTmpFs(Map.of("/usr/share/elasticsearch/data", "rw"))。容器设置将如下所示:
static ElasticsearchContainer elasticsearch =new ElasticsearchContainer(ELASTICSEARCH_IMAGE)// other instructions.withTmpFs(Map.of("/usr/share/elasticsearch/data", "rw"));
存储速度越慢,性能提升就越显著,因为 Elasticsearch 现在将写入和读取 RAM 中的临时文件系统。
注意:
顾名思义,这是一个临时文件系统,也就是说它不是持久性的。因此,此解决方案仅适用于测试。请勿在生产中使用它,因为它可能会导致数据丢失。
要评估此解决方案可以在多大程度上提高硬件性能, 你可以尝试标签 tmpfs。
更多工作,相同时间
产品代码库的大小在活跃开发阶段增长最快。然后,当它进入维护阶段(如果适用)时,通常只涉及错误修复。但是,测试库的大小会不断增长,因为功能和错误都需要通过测试来覆盖,以防止回归。理想情况下,错误修复应始终伴随着测试,以防止错误再次出现。这意味着即使开发不是特别活跃,测试的数量也会不断增加。本节中描述的方法提供了有关如何在不显着增加测试套件持续时间的情况下管理不断增长的测试库的提示,前提是有足够的资源来实现并行化。
为简单起见,我们假设示例中的测试用例数量增加了一倍(而不是编写额外的测试,我们将复制现有的测试用例来进行此演示)。
在最简单的方法中,我们可以向 BookSearcherIntTest 类添加三个 @Test 方法。然后,我们可以以一种有点非正统的方式使用 Java 的一个分析器:Java Flight Recorder 来观察 CPU 和内存消耗。由于我们已将其添加到 POM 中,因此在运行测试后,我们可以在主目录中打开 recording-1.jfr。结果在 Environment -> Processes 中可能如下所示:
如你所见,在一个类中运行六个测试使所需时间增加了一倍。此外,上面的 CPU 使用率图表中的主要颜色是……根本没有颜色,因为 CPU 利用率在高峰时刻几乎达不到 20%。当你为使用时间付费时(无论是向云提供商付费还是以你自己的挂钟时间来获得有意义的反馈),未充分利用 CPU 是一种浪费。
你使用的 CPU 很可能有多个核心。这里的优化是将工作负载分成两部分,这应该大约将持续时间减半。为了实现这一点,我们将新添加的测试移到另一个名为 BookSearcherAnotherIntTest 的类中,并指示 Maven 使用 -DforkCount=2 运行两个分支进行测试。完整命令变为:
./mvnw test '-Dtest=*IntTest*' -DforkCount=2
在这里,CPU 的利用率更高。
不应将重点放在确切的数字上来解释此示例。相反,重要的是不仅适用于 Java 的总体趋势:
- 检查你的 CPU 在测试期间是否得到正确利用。
- 如果没有,请尝试尽可能多地并行化你的测试(尽管其他资源有时可能会限制你)。
- 请记住,不同的环境可能需要不同的并行化因素(例如,Maven 中的 -DforkCount=N)。最好避免在构建脚本中硬编码这些因素,而是根据项目和环境对其进行调整:
- 如果只运行一个测试类,则可以跳过开发人员机器(developer machines)的这一步骤。
- 对于功能较弱的 CI 环境,较低的数字可能就足够了。
- 对于功能更强大的 CI 设置,较高的数字可能效果很好。
对于 Java,重要的是避免使用一个大类,而是尽可能将测试分成较小的类。不同的并行化技术和参数适用于其他技术堆栈,但总体目标仍然是充分利用你的硬件资源。
为了进一步完善,请避免在测试类中重复设置代码。将测试本身与基础架构/设置代码分开。例如,应将配置元素(如镜像版本声明)放在一个地方。在 Java 版 Testcontainers 中,我们可以使用(或稍微重新利用)继承来确保在测试之前加载(并执行)包含基础架构代码的类。结构如下所示:
class CommonTestBase {// Containers' declarations, startup, and data handling code here
}class BookSearcherIntTest extends CommonTestBase {// Integration tests, ideally for one service
}class AnotherServiceIntTest extends CommonTestBase {// More integration tests, ideally for another service
}
如需完整的演示,请再次参考 GitHub 上的示例项目。
重用 - 仅启动一次
本文中介绍的最后一种技术对于开发人员机器(eveloper machines)特别有用。它可能不适用于传统的 CI(例如,内部托管的 Jenkins),并且对于临时 CI 环境(如基于云的 CI,其中构建机器是一次性使用的,每次构建后都会退役)通常是不必要的。此技术依赖于 Testcontainers 的预览功能,称为重用。
通常,测试套件完成后会自动清理容器。这种默认行为非常方便,尤其是在长期运行的 CI 中,因为它可以确保无论测试结果如何都不会剩余容器。但是,在某些情况下,我们可以让容器在测试之间保持运行,以便后续测试不会浪费时间再次启动它。这种方法对于在较长时间内(有时是几天)开发功能或修复错误(其中重复运行相同的测试(类))的开发人员特别有益。
如何启用重用
启用重用是一个两步过程:
1. 在声明容器时将其标记为可重用:
static ElasticsearchContainer elasticsearch =new ElasticsearchContainer(ELASTICSEARCH_IMAGE)// other instructions.withReuse(true);
2. 选择在合适的环境中启用重用功能(例如,在你的开发机器上)。在开发人员工作站上执行此操作的最简单、最持久的方法是确保 $HOME 目录中的配置文件具有正确的内容。在 ~/.testcontainers.properties 中,包含以下行:
testcontainers.reuse.enable=true
就这样!首次使用时,测试不会更快,因为容器仍需要启动。但是,在初始测试之后:
- 运行 docker ps 将显示容器仍在运行(这现在是一项功能,而不是错误)。
- 后续测试将更快。
注意:
一旦启用重用,手动停止容器就成为你的责任。
利用快照或初始化数据实现重用
重用功能与仅将初始化数据文件复制到容器一次或使用快照等技术结合使用效果特别好。启用重用后,无需为后续测试重新创建快照,从而节省更多时间。所有优化部分都开始落实到位。
重复使用分叉容器
虽然重复使用在许多情况下效果很好,但在第二次运行期间将重复使用与多个分叉相结合时会出现问题。这可能会导致与容器或 Elasticsearch 处于不正确状态相关的错误或乱码输出。如果你希望同时使用这两项改进(例如,在提交 PR 之前在功能强大的工作站上运行许多集成测试),则需要进行额外的调整。
问题
问题可能表现为以下错误:
co.elastic.clients.elasticsearch._types.ElasticsearchException: [es/esql.query] failed: [illegal_index_shard_state_exception] CurrentState[RECOVERING] operations only allowed when shard state is one of [POST_RECOVERY, STARTED]
发生这种情况的原因在于 Testcontainers 如何识别可重复使用的容器。
当两个分支都启动且没有 Elasticsearch 容器运行时,每个分支都会初始化自己的容器。 但是,重新启动后,每个分支都会查找可重复使用的容器并找到一个。 由于所有容器看起来与 Testcontainers 相同,因此两个分支可能会选择同一个容器。 这会导致竞争条件,其中多个分支尝试使用同一个 Elasticsearch 实例。 例如,一个分支可能正在恢复快照,而另一个分支正在尝试执行相同操作,从而导致上述错误。
解决方案
为了解决这个问题,我们需要引入容器之间的差异,并确保分支根据这些差异确定性地选择容器。
步骤 1:更新 pom.xml
修改 pom.xml 中的 Surefire 配置以包含以下内容:
<environmentVariables><fork>fork_${surefire.forkNumber}</fork>
</environmentVariables>
这会为每个 fork 添加一个唯一标识符 (fork_${surefire.forkNumber}) 作为环境变量。
第 2 步:修改容器声明
调整代码中的 Elasticsearch 容器声明,以包含基于 fork 标识符的标签:
static ElasticsearchContainer elasticsearch =new ElasticsearchContainer(ELASTICSEARCH_IMAGE)// other settings.withLabel("fork", System.getenv().getOrDefault("fork", "fork_1"));
效果
这些更改确保每个分支都会创建并使用自己的容器。由于标签独特,容器略有不同,允许测试容器将它们确定性地分配给特定分支。
这种方法消除了竞争条件,因为没有两个分支会尝试重复使用同一个容器。重要的是,容器内的 Elasticsearch 功能保持不变,并且可以在分支之间动态分配测试而不会影响结果。
它真的值得吗?
正如本文开头所警告的那样,这里介绍的改进应谨慎应用,因为它们会使我们的测试设置代码变得不那么直观。有什么好处?
我们以在我的计算机上大约 25 秒的三个集成测试开始本文。在应用所有改进并将实际测试数量增加一倍至六个之后,我笔记本电脑上的执行时间下降到 8 秒。测试数量增加了一倍;构建时间缩短了三分之二。由你来决定它是否适合你的情况。;-)
它不止于此
这个关于使用真实 Elasticsearch 进行测试的迷你系列到此结束。在第一部分中,我们讨论了何时模拟 Elasticsearch 索引是有意义的,以及何时进行集成测试是一个更好的主意。在第二部分中,我们解决了导致集成测试变慢的最常见错误。第三部分更加努力,使集成测试运行得更快,只需几秒钟而不是几分钟。
还有更多方法可以优化你的体验并降低使用 Elasticsearch 进行系统集成测试相关的成本。不要犹豫,探索这些可能性并尝试你的技术堆栈。
如果你的案例涉及上述任何技术,或者你有任何疑问,请随时通过我们的讨论论坛或社区 Slack 频道与我们联系。
想要获得 Elastic 认证?了解下一次 Elasticsearch 工程师培训何时开始!
Elasticsearch 包含新功能,可帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本以了解更多信息,开始免费云试用,或立即在你的本地机器上试用 Elastic。
原文:Advanced integration tests with real Elasticsearch - Elasticsearch Labs
相关文章:
使用真实 Elasticsearch 进行高级集成测试
作者:来自 Elastic Piotr Przybyl 掌握高级 Elasticsearch 集成测试:更快、更智能、更优化。 在上一篇关于集成测试的文章中,我们介绍了如何通过改变数据初始化策略来缩短依赖于真实 Elasticsearch 的集成测试的执行时间。在本期中࿰…...
统计学中的样本概率论中的样本
不知道当初谁想的把概率论和数理统计合并,作为一门课。这本身是可以合并,完整的一条线,看这里。但是,作为任课老师应该从整体上交代清楚,毕竟是两个学科,不同的学科合并必然会有各种不协调的问题。 举个最…...
SQL 总结
SQL 总结 引言 SQL(Structured Query Language)是一种用于管理关系数据库的计算机语言。自从1970年代被发明以来,SQL已经成为了数据库管理的基础。本文将对SQL的基本概念、常用命令、高级特性以及SQL在数据库管理中的应用进行总结。 SQL基本概念 数据库 数据库是存储数…...
Openfga 授权模型搭建
1.根据项目去启动 配置一个 openfga 服务器 先创建一个 config.yaml文件 cd /opt/openFGA/conf touch ./config.yaml 怎么配置? 根据官网来看 openfga/.config-schema.json at main openfga/openfga GitHub 这里讲述详细的每一个配置每一个类型 这些配置有…...
【Proteus】NE555纯硬件实现LED呼吸灯效果,附源文件,效果展示
本文通过NE555定时器芯片和简单的电容充放电电路,设计了一种纯硬件实现的呼吸灯方案,并借助Proteus仿真软件验证其功能。方案无需编程,成本低且易于实现,适合电子爱好者学习PWM(脉宽调制)和定时器电路原理。 一、呼吸灯原理与NE555功能分析 1. 呼吸灯核心原理 呼吸灯的…...
DRM系列三:drm core模块入口
本系列文章基于linux 5.15 一、drm_core_init 执行一些drm core的初始化工作 static int __init drm_core_init(void) {int ret;drm_connector_ida_init();idr_init(&drm_minors_idr);drm_memcpy_init_early();ret drm_sysfs_init();if (ret < 0) {DRM_ERROR("…...
Clock Controller of RH850/F1KH-D8, RH850/F1KM-S4, RH850/F1KM-S2
&esmp; 时钟控制器由时钟振荡电路、时钟选择电路、和时钟输出电路组成。 RH850/F1KH、RH850/F1KM单片机的时钟控制器具有以下特点: 六个片上时钟振荡器: 主振荡器(MainOSC),振荡频率分别为8、16、20和24 MHz子振荡器(SubOSC),振荡频率为32.768 kHz*1 100针的产品…...
kamailio-auth模块详解【以下内容来源于官网,本文只做翻译】
以下是《Auth 模块》文档的中文翻译: Auth 模块 作者:Jan Janak FhG Fokus janiptel.org Juha Heinanen TutPro Inc jhsong.fi Daniel-Constantin Mierla asipto.com micondagmail.com 版权所有 © 2002, 2003 FhG FOKUS 官网链接: https://kamaili…...
从TypeScript到ArkTS的适配指导
文章目录 一、ArkTS语法适配背景程序稳定性程序性能.ets代码兼容性支持与TS/JS的交互方舟运行时兼容TS/JS二、从TypeScript到ArkTS的适配规则概述强制使用静态类型禁止在运行时变更对象布局限制运算符的语义不支持 structural typing约束说明限制使用标准库一、ArkTS语法适配背…...
Git 版本控制:基础介绍与常用操作
目录 Git 的基本概念 Git 安装与配置 Git 常用命令与操作 1. 初始化本地仓库 2. 版本控制工作流程 3. 分支管理 4. 解决冲突 5. 回退和撤销 6. 查看提交日志 前言 在软件开发过程中,开发者常常需要在现有程序的基础上进行修改和扩展。但如果不加以管理&am…...
【Python】理解Python中的协程和生成器:从yield到async
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代编程中,异步编程成为提升程序性能和响应速度的重要手段。Python作为一门功能强大的编程语言,提供了丰富的工具来实现异步操作,其中…...
Unity开发游戏使用XLua的基础
Unity使用Xlua的常用编码方式,做一下记录 1、C#调用lua 1、Lua解析器 private LuaEnv env new LuaEnv();//保持它的唯一性void Start(){env.DoString("print(你好lua)");//env.DoString("require(Main)"); 默认在resources文件夹下面//帮助…...
什么是区块链
区块链是一种去中心化的分布式账本技术,它通过一系列复杂而精密的设计原则和机制来确保数据的安全性、透明性和不可篡改性。在最基础的层面上,区块链是由一系列按照时间顺序链接起来的数据块组成的链式结构。每个数据块中包含了一定数量的交易记录或状态…...
C++中的析构器(Destructor)(也称为析构函数)
在C中,析构器(Destructor)也称为析构函数,它是一种特殊的成员函数,用于在对象销毁时进行资源清理工作。以下是关于C析构器的详细介绍: 析构函数的特点 名称与类名相同,但前面有一个波浪号 ~&a…...
【ts + java】古玩系统开发总结
src别名的配置 开发中文件和文件的关系会比较复杂,我们需要给src文件夹一个别名吧 vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue import path from path// https://vitejs.dev/config/ export default defineConfig({pl…...
NLP深度学习 DAY5:Sequence-to-sequence 模型详解
Seq2Seq(Sequence-to-Sequence)模型是一种用于处理输入和输出均为序列任务的深度学习模型。它最初被设计用于机器翻译,但后来广泛应用于其他任务,如文本摘要、对话系统、语音识别、问答系统等。 核心思想 Seq2Seq 模型的目标是将…...
音视频多媒体编解码器基础-codec
如果要从事编解码多媒体的工作,需要准备哪些更为基础的内容,这里帮你总结完。 因为数据类型不同所以编解码算法不同,分为图像、视频和音频三大类;因为流程不同,可以分为编码和解码两部分;因为编码器实现不…...
数据分析系列--⑦RapidMiner模型评价(基于泰坦尼克号案例含数据集)
一、前提 二、模型评估 1.改造⑥ 2.Cross Validation算子说明 2.1Cross Validation 的作用 2.1.1 模型评估 2.1.2 减少过拟合 2.1.3 数据利用 2.2 Cross Validation 的工作原理 2.2.1 数据分割 2.2.2 迭代训练与测试 2.2.3 结果汇总 …...
【react+redux】 react使用redux相关内容
首先说一下,文章中所提及的内容都是我自己的个人理解,是我理逻辑的时候,自我说服的方式,如果有问题有补充欢迎在评论区指出。 一、场景描述 为什么在react里面要使用redux,我的理解是因为想要使组件之间的通信更便捷…...
nacos 配置管理、 配置热更新、 动态路由
文章目录 配置管理引入jar包添加 bootstrap.yaml 文件配置在application.yaml 中添加自定义信息nacos 配置信息 配置热更新采用第一种配置根据服务名确定配置文件根据后缀确定配置文件 动态路由DynamicRouteLoaderNacosConfigManagerRouteDefinitionWriter 路由配置 配置管理 …...
前端知识速记:节流与防抖
前端知识速记:节流与防抖 什么是防抖? 防抖是一种控制事件触发频率的方法,通常用于处理用户频繁触发事件的场景。防抖的核心思想是将多个连续触发事件合并为一个事件,以减少执行次数。它在以下场景中特别有效: 输入…...
2.攻防世界PHP2及知识点
进入题目页面如下 意思是你能访问这个网站吗? ctrlu、F12查看源码,什么都没有发现 用kali中的dirsearch扫描根目录 命令如下,根据题目提示以及需要查看源码,扫描以php、phps、html为后缀的文件 dirsearch -u http://61.147.17…...
【ubuntu】双系统ubuntu下一键切换到Windows
ubuntu下一键切换到Windows 1.4.1 重启脚本1.4.2 快捷方式1.4.3 移动快捷方式到系统目录 按前文所述文档,开机默认启动ubuntu。Windows切换到Ubuntu直接重启就行了,而Ubuntu切换到Windows稍微有点麻烦。可编辑切换重启到Windows的快捷方式。 1.4.1 重启…...
C#属性和字段(访问修饰符)
不同点逻辑性/灵活性存储性访问性使用范围安全性属性(Property)源于字段,对字段的扩展,逻辑字段并不占用实际的内存可以被其他类访问对接收的数据范围做限定,外部使用增加了数据的安全性字段(Field)不经过逻辑处理占用内存的空间及位置大部分字段不能直接被访问内存使用不安全 …...
Androidstdio-真机调试
显示隐藏设备 手机通过数据线插入电脑 Androidstdio设置中下载USB驱动 选择下载的驱动 更新完成后,在编译器查看,此时真机已经显示出来了 调试app可以在日志中查看日志,详细日志查看方法看前面的帖子 如果有这种日志输出,运行到此…...
2025年美赛B题-结合Logistic阻滞增长模型和SIR传染病模型研究旅游可持续性-成品论文
模型设计思路与创新点: 建模的时候应该先确定我们需要建立什么类的模型?优化类还是统计类?这个题需要大量的数据分析,因此我们可以建立一个统计学模型。 统计学建模思路:观察规律,建立模型,参…...
数据结构【链栈】
基于 C 实现链表栈:原理、代码与应用 一、引言 栈就是一个容器,可以当场一个盒子,只能一个一个拿,一个一个放,而且是从上面放入。 有序顺序栈操作比较容易【会了链栈之后顺序栈自然明白】,所以我们这里只…...
MediaPipe与YOLO已训练模型实现可视化人脸和手势关键点检测
项目首页 - ZiTai_YOLOV11:基于前沿的 MediaPipe 技术与先进的 YOLOv11 预测试模型,精心打造一款强大的实时检测应用。该应用无缝连接摄像头,精准捕捉画面,能即时实现人脸检测、手势识别以及骨骼关键点检测,将检测结果实时、直观地…...
使用 SpringBoot+Thymeleaf 模板引擎进行 Web 开发
目录 一、什么是 Thymeleaf 模板引擎 二、Thymeleaf 模板引擎的 Maven 坐标 三、配置 Thymeleaf 四、访问页面 五、访问静态资源 六、Thymeleaf 使用示例 七、Thymeleaf 常用属性 前言 在现代 Web 开发中,模板引擎被广泛用于将动态内容渲染到静态页面中。Thy…...
pytorch深度Q网络
人工智能例子汇总:AI常见的算法和例子-CSDN博客 DQN 引入了深度神经网络来近似Q函数,解决了传统Q-learning在处理高维状态空间时的瓶颈,尤其是在像 Atari 游戏这样的复杂环境中。DQN的核心思想是使用神经网络 Q(s,a;θ)Q(s, a; \theta)Q(s,…...
list的使用,及部分功能的模拟实现(C++)
目录(文章中"节点"和"结点"是同一个意思) 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers 1.2.6 list…...
makailio-alias_db模块详解
ALIAS_DB 模块 作者 Daniel-Constantin Mierla micondagmail.com Elena-Ramona Modroiu ramonaasipto.com 编辑 Daniel-Constantin Mierla micondagmail.com 版权 © 2005 Voice Sistem SRL © 2008 asipto.com 目录 管理员指南 概述依赖 2.1 Kamailio 模块 2.2 外…...
【AI】DeepSeek 概念/影响/使用/部署
在大年三十那天,不知道你是否留意到,“deepseek”这个词出现在了各大热搜榜单上。这引起了我的关注,出于学习的兴趣,我深入研究了一番,才有了这篇文章的诞生。 概念 那么,什么是DeepSeek?首先百…...
算法随笔_35: 每日温度
上一篇:算法随笔_34: 最后一个单词的长度-CSDN博客 题目描述如下: 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升…...
人工智能入门课【手写自注意力机制】
原理 自注意力(Self-Attention)是一种强大的机制,广泛应用于自然语言处理、计算机视觉等领域,尤其是在Transformer架构中发挥了关键作用。它的核心思想是让模型能够动态地关注输入序列中不同位置之间的关系,从而更好地…...
记7(激活函数+多层神经网络+梯度下降法及其优化
目录 1、激活函数1.1、sigmoid函数:2端饱和,下面2个函数都要幂运算,运算速度会比较慢1.2、ReLU函数(Rectified Linear Unit,修正线性单元)1.3、PReLU函数(Parameteric Rectified Linear Unit&am…...
Qt u盘自动升级软件
Qt u盘自动升级软件 Chapter1 Qt u盘自动升级软件u盘自动升级软件思路:step1. 获取U盘 判断U盘名字是否正确, 升级文件是否存在。step2. 升级step3. 升级界面 Chapter2 Qt 嵌入式设备应用程序,通过U盘升级的一种思路Chapter3 在开发板上运行的…...
关于低代码技术架构的思考
我们经常会看到很多低代码系统的技术架构图,而且经常看不懂。是因为技术架构图没有画好,还是因为技术不够先进,有时候往往都不是。 比如下图: 一个开发者,看到的视角往往都是技术层面,你给用户讲React18、M…...
如何使用 ChatBox AI 简化本地模型对话操作
部署模型请看上一篇帖子:本地部署DeepSeek教程(Mac版本)-CSDN博客 使用 ChatBox AI 简化本地模型对话操作: 打开 ChatBox AI 官网:Chatbox AI官网:办公学习的AI好助手,全平台AI客户端…...
缩位求和——蓝桥杯
1.题目描述 在电子计算机普及以前,人们经常用一个粗略的方法来验算四则运算是否正确。 比如:248153720248153720 把乘数和被乘数分别逐位求和,如果是多位数再逐位求和,直到是 1 位数,得 24814>145 156 56 而…...
hexo部署到github page时,hexo d后page里面绑定的个人域名消失的问题
Hexo 部署博客到 GitHub page 后,可以在 setting 中的 page 中绑定自己的域名,但是我发现更新博客后绑定的域名消失,恢复原始的 githubio 的域名。 后面搜索发现需要在 repo 里面添加 CNAME 文件,内容为 page 里面绑定的域名&…...
neo4j入门
文章目录 neo4j版本说明部署安装Mac部署docker部署 neo4j web工具使用数据结构图数据库VS关系数据库 neo4j neo4j官网Neo4j是用ava实现的开源NoSQL图数据库。Neo4作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理&am…...
代码随想录——回溯
文章目录 组合组合总数电话号码的字母组合组合总数组合总数Ⅱ分割回文串复原IP地址子集子集Ⅱ非递减子序列去重的实现方法方法 1:**排序 跳过重复元素**方法 2:**使用哈希表或数组记录已使用的数字** 去重的完整示例总结本题代码 全排列全排列Ⅱ重新安排…...
独立游戏RPG回顾:高成本
刚看了某纪录片, 内容是rpg项目的回顾。也是这个以钱为核心话题的系列的最后一集。 对这期特别有代入感,因为主角是曾经的同事,曾经在某天晚上听过其项目组的争论。 对其这些年的起伏特别的能体会。 主角是制作人,在访谈中透露这…...
SQLModel入门
目录 概述快速开始官方教程简单使用样例 概述 SQLModel 是一个 ORM 框架,其基于 SQLAlchemy 和 Pydantic,其中 SQLALchemy 提供底层 ORM 能力,Pydantic 提供类型校验能力,SQLModel 中,一个 SQLModel model 既是一个 S…...
关于MySQL InnoDB存储引擎的一些认识
文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的?1.1 MySQL的存储引擎有哪些?1.2 MyIsam和InnoDB有什么区别? 2.MySQL表的结构是什么?2.1 行结构是什么样呢?2.1.1 NULL列表?2.1.2 char和varc…...
【学习笔记】深度学习网络-正则化方法
作者选择了由 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 三位大佬撰写的《Deep Learning》(人工智能领域的经典教程,深度学习领域研究生必读教材),开始深度学习领域学习,深入全面的理解深度学习的理论知识。 在之前的文章中介绍了深度学习中用…...
NVIDIA (英伟达)的 GPU 产品应用领域
游戏娱乐领域 PC 游戏:NVIDIA 的 GeForce 系列 GPU 是 PC 游戏玩家的首选之一。能实现实时光线追踪、高分辨率渲染等,使游戏画面更加逼真,如《赛博朋克 2077》等支持光线追踪的游戏,在 NVIDIA GPU 的加持下,可呈现出真…...
Docker快速部署高效照片管理系统LibrePhotos搭建私有云相册
文章目录 前言1.关于LibrePhotos2.本地部署LibrePhotos3.LibrePhotos简单使用4. 安装内网穿透5.配置LibrePhotos公网地址6. 配置固定公网地址 前言 想象一下这样的场景:你有一大堆珍贵的回忆照片,但又不想使用各种网盘来管理。怎么办?别担心…...
goframe 多语言国际化解决方案
项目背景 本项目采用基于JSON配置的多语言国际化(i18n)解决方案,支持多种语言的无缝切换和本地化。 目录结构 manifest/ └── i18n/├── zh.json # 简体中文├── zh-tw.json # 繁体中文├── en.json # 英语├…...