C++20 module下的LVGL模拟器
ARM GCC:14.2
Toolchain:MSVC
前篇:使用SDL2搭建简易LVGL模拟器_lvgl sdl-CSDN博客
故事
从前
我所用的单片机工程本身是为了电赛设计的,由于电赛的特性,需要使用同一个实验平台通过不同外设的“排列组合”来实现不同实验项目的功能,也就是说外设基本只要开发一次即可复用(BSP层),唯一不同的是“不同的项目需要调用不同的外设、编写不同的逻辑来实现不同的功能”。遇到新的项目,也只是编写新的外设的控制代码,基本框架并不需要改变
在这个基础上,设计了这种的项目组织结构,同一个工程包含了不同的项目代码,BSP层、HAL层等都是共用的,包括main.cpp
不同项目的逻辑是编写在app.cpp里的(放在一个个独立的文件夹里),main.cpp通过extern来调用app.cpp里的接口,通过CMakeLists来选择编译哪个项目的app.cpp。如果需要实现更加复杂的功能,比如GUI、AI等,那么在项目文件夹里添加更多目录或者文件,通过CMakeLists选择性编译不同项目文件夹的所有源文件即可。
后来
起初为了兼容性,单片机的BSP(那些外设驱动)都是使用纯C编写的。可是随着开发的BSP驱动变多,要写的.h/c文件也变多,代码也越编写越杂乱,各种宏、全局变量等漫天飞。同时为了保证不同项目的一致性,比如有些项目需要使用GUI和RTOS,有些不需要。那么需要让main.cpp、ISR.cpp(中断处理)等共用的文件做出一些适配,那么又是一堆宏和子cmake里的一堆变量(虽然现在也没解决)。
后面想到工程本身就是为了电赛设计的,为何不依此一路走到黑?于是把搁置了许久的命名空间和C++20 module特性又重新启用了,抛弃了.h/c文件,改用.ixx文件。好处还不少:
- 首先就是编写驱动代码在一个文件里即可,不需要在.h/c文件里到处折腾,来回修改函数签名,也不需要建立include和source目录
- 代码在一个文件里,编译器能看到所有的代码,可以进行更好的优化。之前在.h/c中为了内联,不惜在头文件里要么直接定义static inline函数,要么使用#define和\配合。结果就是,想要内联就需要在头文件里写东西,而在头文件里写太多东西,就会让编译线性增长,而且里面的东西暴露的到处都是,代码补全提示里全是乱七八糟的东西。(使用LTO既慢,又容易出现未定义的问题)
- module特性可以很方便导出想要暴露的接口,其余的默认封闭。而命名空间让代码的组织清晰了不少,不同层分配在不同的命名空间。此外,模板、类、重载、引用等特性也都可以使用
- ……
改变
如下,lcd.ixx里由于使用了lvgl,只需要暴露初始化和涂块函数即可,其余函数和宏等仅在内部暴露
也可以使用模板类进行封装
既如此,那么在lvgl的封装中也使用该特性(参考LVGL使用过程中的一点启发),那么模拟器的画风就变成了这样(虽然代码风格上没怎么变)
命名空间的关系如下顶层命名空间是gui,里面分成三个部分,compose是用来存放组件的命名空间,里面包含了各种组件类的定义。Render是个类,负责对lvgl的初始化和运行的封装,widgets是用来存放组件定义的命名空间
在ui文件里,需要完成这些功能
代码层面,ui文件的编写风格也就是变成了这样(由python脚本自动生成)
module; #include <lvgl.h> export module gui:ui; export import :render; // 导入其他资源 /*!USER_DECLARE_BEGIN!*/ import ui_data;/*!USER_DECLARE_END!*/// ---------------- 导出并加载资源 ---------------- extern "C" {// 字体资源LV_FONT_DECLARE(lv_customer_font_SourceHanSerifSC_Regular_13)/*!USER_DECLARE_BEGIN!*//*!USER_DECLARE_END!*/// 图片资源LV_IMG_DECLARE(_dianzisheji_RGB565A8_61x42)/*!USER_DECLARE_BEGIN!*//*!USER_DECLARE_END!*/// 其他/*!USER_DECLARE_BEGIN!*//*!USER_DECLARE_END!*/ }// ---------------- 导出并定义组件 ---------------- export namespace gui::widgets::main {using namespace gui::compose;// 命名方式看个人习惯inline Image img_screen_img_1;inline Chart chart_screen_1;inline Button btn_screen_1;inline Label label_screen_1;inline Button btn_screen_2;inline Label label_screen_2;inline Button btn_screen_3;inline Label label_screen_3;inline Button btn_screen_4;inline Label label_screen_4;inline Button btn_screen_5;/*为了演示,删除了一些组件定义代码……*//*!USER_DECLARE_BEGIN!*/inline Timer updata_timer;/*!USER_DECLARE_END!*/ }// ======================= 用户空间 ======================= /*!USER_DECLARE_BEGIN!*/ // 全局变量定义 inline uint8_t length = 200; inline uint8_t wave_start_index = 0; inline uint16_t array_length = 400; inline size_t current_index = 0; // 当前读取位置 inline uint8_t count = 0;/*!USER_DECLARE_END!*/ // ======================= 用户空间 =======================// ---------------- 导出用户接口 ---------------- export namespace gui::ui {using namespace gui::widgets::main; // 使用组件命名空间/*!USER_DECLARE_BEGIN!*/// 类声明class Osc{public:static auto initChartComponent() -> void;// 生成随机数据static inline auto generate_data() -> void;static inline auto toggle_generation() -> void;// 新增定时器回调函数static void timer_cb(lv_timer_t *timer){if (is_generating){generate_data();}}static inline auto set_cursor_on_press() -> void{chart_screen_chart_1.set_cursor_pos_on_pressed(cursor);if (had_generated){char buf[10];lv_snprintf(buf, sizeof(buf), "%d %d", chart_screen_chart_1.get_pressed_point(),chart_screen_chart_1.get_cursor_point_y(series)); //格式化点数值成字符串label_screen_label_1.text(buf);}}static inline bool had_generated = false;private:// 添加生成状态标志static inline bool is_generating = false;static inline ChartSeries_t series{}; //数据 系列1static inline ChartCursor_t cursor{}; //光标 系列1static inline lv_point_t cursor_point{}; //光标 系列1};/*!USER_DECLARE_END!*/ }// ---------------- 初始化UI和事件 ---------------- export namespace gui {void Render::screenInit(){using namespace gui::widgets::main; // 使用组件命名空间scr.bg_color(lv_color_hex(0xffffff)).bg_grad_dir(LV_GRAD_DIR_NONE);img_screen_img_1.init().pos(405, 5).size(61, 42).add_flag(LV_OBJ_FLAG_CLICKABLE).src(&_dianzisheji_RGB565A8_61x42).pivot(50, 50).image_recolor_opa(0);chart_screen_1.init().pos(18, 8).size(375, 227).scrollbar_mode(LV_SCROLLBAR_MODE_OFF).div_count(11, 15).point_count(5).range(LV_CHART_AXIS_PRIMARY_Y).range(LV_CHART_AXIS_SECONDARY_Y).bg_color(lv_color_hex(0xffffff)).bg_grad_dir(LV_GRAD_DIR_NONE).border_width(1).border_opa(255).border_color(lv_color_hex(0xe8e8e8)).border_side(LV_BORDER_SIDE_FULL).radius(0).line_width(2).line_color(lv_color_hex(0xe8e8e8));label_screen_1_label.init(btn_screen_1).text("BB").center().width(LV_PCT(100));/*为了演示,删除了一些初始化代码……*//*!USER_DECLARE_BEGIN!*/ui::Osc::initChartComponent();/*!USER_DECLARE_END!*/}void Render::eventInit(){using namespace gui::widgets::main; // 使用组件命名空间/*!USER_DECLARE_BEGIN!*/// 绑定 随机生成数据事件btn_screen_1.OnClicked<ui::Osc::toggle_generation>();updata_timer.create(ui::Osc::timer_cb, 20);chart_screen_1.OnPressed<ui::Osc::set_cursor_on_press>();/*!USER_DECLARE_END!*/} }// ---------------- 模块内部实现 ---------------- namespace gui::ui {// 新增切换生成状态的方法auto Osc::toggle_generation() -> void{is_generating = !is_generating;had_generated = true;// 更新按钮文本label_screen_1.text(is_generating ? "BB" : "LL");if (is_generating){updata_timer.resume();}else{updata_timer.pause();}}auto Osc::generate_data() -> void{// 批量设置128个点for (int i = 0; i < 128; ++i){// 循环访问数组size_t idx = (current_index + i) % RAND_POOL_SIZE;chart_screen_1.next_value(series, rand_pool[idx]);}}auto Osc::initChartComponent() -> void{series = chart_screen_1.update_mode(LV_CHART_UPDATE_MODE_SHIFT) // 改为SHIFT模式.line_color(lv_color_hex(0x34e6ff)).point_count(128).remove_dot().add_series(lv_color_hex(0x34e6ff));cursor = chart_screen_1.add_cursor(lv_color_hex(0xfffb00), LV_DIR_ALL);scale_screen_1.border_opa(0);} }
结果
不过这些好处仅限arm交叉编译工具链gcc 14.2,在MinGW64中的gcc 14.2里可谓是一塌糊涂。理论上gcc版本相同对特性的支持就应该相同或者大差不差,结果在同一份代码的实际测试中,后者对module特性的支持竟然比前者要差一些。原本inline 变量这个特性在C++17中就已经实现了,但是后者对下面这样的代码竟然能报出重定义的错误,敢情是C++20的module特性与C++17的inline特性冲突了
export namespace gui::widgets::main {using namespace gui::compose;// 使用命名空间inline Component scr;// 主屏幕 }
转机
既然MinGW GCC无法胜任,那么只好转为使用对module特性支持更好的MSVC工具链(需要下载Visual Studio)
与此同时,需要下载SDL2的VC版,打开链接Releases · libsdl-org/SDL,找到VC版
下载解压后,里面的内容与左边的框框一致
为了在CMakeLists里与GCC的SDL2库路径保持一致,在右边的框里添加了一个SDL2目录
# 自动识别工具链类型 !!切换工具链时需要把cmake产物删除干净!! if(MSVC)# Visual Studio 工具链set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/VC")set(SDL2_LIB_DIR "${SDL2_ROOT}/lib/x64")message(STATUS "[Config] Using MSVC toolchain") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")# 区分MinGW架构message(WARNING "[Config] MinGW64 GCC 14.2 对module和inline特性的支持不完善,会出问题")if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SIZEOF_VOID_P EQUAL 8)set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/x86_64-w64-mingw32")message(STATUS "[Config] Using 64-bit MinGW")else()set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/i686-w64-mingw32")message(STATUS "[Config] Using 32-bit MinGW")endif()set(SDL2_LIB_DIR "${SDL2_ROOT}/lib") else()message(FATAL_ERROR "[Config] Unsupported toolchain: ${CMAKE_CXX_COMPILER_ID}") endif()# …………target_include_directories(${PROJECT_NAME} PRIVATE ${SDL2_ROOT}/include)
如此一来,便可编译成功
代码
CMakeLists:
cmake_minimum_required(VERSION 3.29) project(Simulator LANGUAGES C CXX) include(common_functions.cmake)# ------------------------ 配置选项 ------------------------ set(PROJECT_DIR ../../../Projects/driversDevelop) set(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..") set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../Middleware/Third_Party")# 自动识别工具链类型 !!切换工具链时需要把cmake产物删除干净!! if(MSVC)# Visual Studio 工具链set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/VC")set(SDL2_LIB_DIR "${SDL2_ROOT}/lib/x64")message(STATUS "[Config] Using MSVC toolchain") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")# 区分MinGW架构message(WARNING "[Config] MinGW64 GCC 14.2 对module和inline特性的支持不完善,会出问题")if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SIZEOF_VOID_P EQUAL 8)set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/x86_64-w64-mingw32")message(STATUS "[Config] Using 64-bit MinGW")else()set(SDL2_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/SDL2/i686-w64-mingw32")message(STATUS "[Config] Using 32-bit MinGW")endif()set(SDL2_LIB_DIR "${SDL2_ROOT}/lib") else()message(FATAL_ERROR "[Config] Unsupported toolchain: ${CMAKE_CXX_COMPILER_ID}") endif()set(LVGL_DIR "${THIRD_PARTY_DIR}/LVGL/lvgl") set(UI_DIR "${PROJECT_DIR}/ui") set(GUI_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../Compose")# 输出目录 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")# ------------------------ 编译选项 ------------------------ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON)# MSVC 专用选项 if (MSVC)# C++20 模块和概念支持string(APPEND CMAKE_CXX_FLAGS " /std:c++latest")# 根据构建类型设置优化选项if (CMAKE_BUILD_TYPE STREQUAL "Release")add_compile_options(/O2)string(APPEND CMAKE_CXX_FLAGS " /RTC0") # Release 禁用运行时检查else()add_compile_options(/Od) # Debug 禁用优化endif()# 调试符号生成add_compile_options(/Zi) else()# GCC/Clang 选项add_compile_options(-O2 -g -fmodules-ts) endif()# ------------------------ 组件库定义 ------------------------ file(GLOB_RECURSE LVGL_SRCS "${LVGL_DIR}/src/*.c" "${LVGL_DIR}/examples/porting/*.c") file(GLOB_RECURSE DRIVERS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/Drivers/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/Drivers/*.cpp") file(GLOB_RECURSE RENDER_SRCS "${PROJECT_ROOT_DIR}/Render/*.c" "${PROJECT_ROOT_DIR}/Render/*.cpp") file(GLOB_RECURSE UI_SRCS "test.cpp" "${UI_DIR}/*.c" "${UI_DIR}/*.cpp") file(GLOB cxx_modules "${GUI_DIR}/*.ixx" "${UI_DIR}/*.ixx")# ------------------------ 可执行目标 ------------------------ add_executable(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")# 添加模块文件 target_sources(${PROJECT_NAME} PUBLICFILE_SET CXX_MODULESBASE_DIRS ${GUI_DIR} ${UI_DIR}FILES ${cxx_modules} )# 添加普通源文件 target_sources(${PROJECT_NAME} PRIVATE${LVGL_SRCS}${DRIVERS_SRCS}${RENDER_SRCS}${UI_SRCS} )# 包含目录 target_include_directories(${PROJECT_NAME} PRIVATE${GUI_DIR}${UI_DIR}${LVGL_DIR}${LVGL_DIR}/examples/porting${CMAKE_CURRENT_SOURCE_DIR}/Drivers${SDL2_ROOT}/include${PROJECT_ROOT_DIR}/Render )# ------------------------ 依赖配置 ------------------------ find_library(SDL2_LIB SDL2 HINTS "${SDL2_LIB_DIR}" REQUIRED)# 查找库 target_link_libraries(${PROJECT_NAME} PRIVATE ${SDL2_LIB})# 链接库# 复制 SDL2.dll add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${SDL2_LIB_DIR}/SDL2.dll"$<TARGET_FILE_DIR:${PROJECT_NAME}> )
模拟器工程还未完善,暂不上传
相关文章:
C++20 module下的LVGL模拟器
ARM GCC:14.2 Toolchain:MSVC 前篇:使用SDL2搭建简易LVGL模拟器_lvgl sdl-CSDN博客 故事 从前 我所用的单片机工程本身是为了电赛设计的,由于电赛的特性,需要使用同一个实验平台通过不同外设的“排列组合”来实现不…...
Go全栈_Golang、Gin实战、Gorm实战、Go_Socket、Redis、Elasticsearch、微服务、K8s、RabbitMQ全家桶
Go全栈全家桶包含: 1、【零基础入门】Go语言核心编程零基础入门实战,B站学习地址分享: 【2025年新版】Go语言教程 2、GolangGinGorm仿小米商城企业级项目实战 3、Golang仿小米商城高并发微服务实战 4、Golang RabbitMQ高并发秒杀、抢购、预约…...
STM32提高篇: 蓝牙通讯
STM32提高篇: 蓝牙通讯 一.蓝牙通讯介绍1.蓝牙技术类型 二.蓝牙协议栈1.蓝牙芯片架构2.BLE低功耗蓝牙协议栈框架 三.ESP32-C3中的蓝牙功能1.广播2.扫描3.通讯 四.发送和接收 一.蓝牙通讯介绍 蓝牙,是一种利用低功率无线电,支持设备短距离通信的无线电技…...
Linux系统编程---精灵进程与守护进程
1、前言 精灵进程又称守护进程、后台进程,在英文中称为 daemon 进程。精灵进程是运行在一个相对干净的环境、不受终端影响、常驻内存的进程,和神话中的精灵一样,拥有不死不灭的特性,长期稳定提供某种功能或服务。 在Linux系统中&a…...
《让机器人读懂你的心:情感分析技术融合奥秘》
机器人早已不再局限于执行简单机械的任务,人们期望它们能像人类伙伴一样,理解我们的喜怒哀乐,实现更自然、温暖的互动。情感分析技术,正是赋予机器人这种“理解人类情绪”能力的关键钥匙,它的融入将彻底革新机器人与人…...
科技项目必须进行验收测试吗?项目验收测试服务机构有哪些?
在现代科技迅猛发展的背景下,各类科技项目层出不穷,从智能硬件到软件系统,乃至工业自动化解决方案,项目的质量直接关系到企业的信誉、用户体验和市场竞争力。那么科技项目必须进行验收测试吗? 简短且明确的回答是:必…...
7.7 Axios+Redux+JWT全链路实战:打通前后端API通信最佳实践
Axios+Redux+JWT全链路实战:打通前后端API通信最佳实践 连接前端与后端 API:全链路数据交互设计指南 关键词:前后端通信架构设计、RESTful API 开发、Axios 请求拦截、Redux 状态管理、JWT 认证集成 1. 前后端通信架构设计原则 我们采用分层架构实现前后端解耦,通过 RES…...
零基础入门 Verilog VHDL:在线仿真与 FPGA 实战全流程指南
摘要 本文面向零基础读者,全面详解 Verilog 与 VHDL 两大主流硬件描述语言(HDL)的核心概念、典型用法及开发流程。文章在浅显易懂的语言下,配合多组可在线验证的示例代码、PlantUML 电路结构图,让你在 EDA Playground 上动手体验数字电路设计与仿真,并深入了解从 HDL 编写…...
[蓝桥杯 2025 省 Python B] 最多次数
import sysdef max_times() -> int:s sys.stdin.readline().strip()checked {l,q,b} # set(),不存在键值对,识别为set()n len(s)time 0i 0while i < n - 2:sec s[i:i3]if set(sec) checked:i 3time 1else:i 1sys.…...
HTTP相关
目录 一、HTTP状态码 1XX信息性状态码 2XX成功状态码 3XX重定向状态码 4XX客户端错误状态码 5XX服务器错误状态码 二、GET/POST/PUT/DELETE请求 2.1GET 2.2POST 2.3PUT 2.4DELETE 2.5RESTful API例子 三、RESTful API 3.1什么是RESTful API 3.2RESTful API中的关…...
使用rclone迁移minio文件
文章目录 一、rclone简介1、工具说明2、核心特点2.1、跨平台支持2.2、多存储支持2.3、加密与安全2.4、增量同步与断点续传2.5、高性能 3、适用场景3.1、云存储迁移3.2、备份与同步3.3、跨云协作3.4、数据加密归档 二、常用命令1、基础操作2、文件传输3、文件管理4、高级功能5、…...
基于Java与MAVLink协议的多无人机(Cube飞控)集群控制与调度方案问题
基于Java与MAVLink协议的多无人机(Cube飞控)集群控制与调度方案问题 背景需求: 我们目前有一个基于Cube飞控的无人机系统,需实现以下核心功能: 多机通信:通过MAVLink协议同时连接并控制多架无人机&#x…...
Super-Vlan和MUX-Vlan的原理、配置、区别
Super-Vlan 原理 Super-Vlan也叫Aggregate-Vlan。 一般的三层交换机中,通常是采用一个VLAN对应一个vlanif接口的方式实现广播域之间的互通,这在某些情况下导致了IP地址的浪费。因为一个VLAN对应的子网中,子网号、子网定向广播地址、子网缺…...
数据一致性问题剖析与实践(二)——单机事务的一致性问题
一、前言 我们一般讲到单机事务,离不开的就是数据库,其最重要的定义就是,要么全部成功执行,要么全部不执行,保证安全的状态转化。 之前我们讨论了几种场景的一致性问题 冗余数据存储中的一致性问题分布式共识中的一…...
VUE Element-ui Message 消息提示组件自定义封装
为了让message 信息提示的更加方便快捷,减少不同地方的调用,避免代码的重复,特意再官方message 组件的基础上二次封装,使代码更加的优雅和高效。 实现效果: 代码组件: 封装成 message.js 文件,…...
HSTL详解
一、HSTL的基本定义 HSTL(High-Speed Transceiver Logic) 是一种针对高速数字电路设计的差分信号接口标准,主要用于高带宽、低功耗场景(如FPGA、ASIC、高速存储器接口)。其核心特性包括: 差分信号传输&…...
【PCB工艺】运放电路中的负反馈机制
通过运算方法器电路设计详细解释负反馈机制(Negative Feedback) 负反馈 是控制系统、电子电路、神经系统等多个领域中非常核心的概念。特别在运算放大器(Op-Amp)电路中,负反馈是实现精确控制和高稳定性的关键机制。 …...
玩转Docker | 使用Docker部署Neko自托管浏览器
玩转Docker | 使用Docker部署Neko自托管浏览器 前言一、Neko介绍简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署Neko服务下载镜像创建容器创建容器检查容器状态检查服务端口安全设置四、访问Neko服务访问Neko首页登录Neko五、基本使用设置键…...
聊聊自动化用例的维护
自动化测试中的农药悖论:为何长期维护至关重要 自动化测试常被视为"一次编写,永久有效"的解决方案,但随着时间的推移,即使设计最精良的测试套件也会逐渐失效。这种现象被称为农药悖论(Pesticide Paradox&am…...
OpenCV 图形API(60)颜色空间转换-----将图像从 YUV 色彩空间转换为 RGB 色彩空间函数YUV2RGB()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将图像从 YUV 色彩空间转换为 RGB。 该函数将输入图像从 YUV 色彩空间转换为 RGB。Y、U 和 V 通道值的常规范围是 0 到 255。 输出图像必须是 8…...
Docker配置带证书的远程访问监听
一、生成证书和密钥 1、准备证书目录和生成CA证书 # 创建证书目录 mkdir -p /etc/docker/tls cd /etc/docker/tls # 生成CA密钥和证书 openssl req -x509 -newkey rsa:4096 -keyout ca-key.pem \ -out ca-cert.pem -days 365 -nodes -subj "/CNDocker CA" 2、为…...
监督学习(Supervised Learning)与无监督学习(Unsupervised Learning)
监督学习与无监督学习是机器学习的两大核心范式,主要区别在于数据是否包含明确的“标签”(目标输出)。 1. 监督学习(Supervised Learning) 定义: 数据形式:输入数据&…...
批量将多个 Excel 表格中的某张图片替换为新的图片
对于 Excel 文档,相信大家都不陌生,我们可以在 Excel 单元格中插入各种各样的图片,我们也可以将 Excel 表格中的图片替换为新的图片,常规的做法我们都是通过 Office 来进行单个处理的,但是如果我们遇到批量处理的场景&…...
数据一致性问题剖析与实践(三)——分布式事务的一致性问题
一、前言 之前我们讨论了几种场景的一致性问题 冗余数据存储中的一致性问题分布式共识中的一致性问题单机事务中的一致性问题 本文将围绕分布式事务中的一致性问题展开讨论。 二、分布式环境的最大难题 相对于单机环境,分布式环境中,一致性问题最大…...
分布式理论和事务
微服务和分布式 微服务 是一种软件架构风格,它将应用程序拆分成一系列小型、独立的服务,每个服务专注于单一功能,彼此通过轻量级通信机制(如 API)进行交互。微服务通常是松耦合的,可以独立开发、部署和扩展…...
基于Flask与Ngrok实现Pycharm本地项目公网访问:从零部署
目录 概要 1. 环境与前置条件 2. 安装与配置 Flask 2.1 创建虚拟环境 2.2 安装 Flask 3. 安装与配置 Ngrok 3.1 下载 Ngrok 3.2 注册并获取 Authtoken 4. 在 PyCharm 中创建 Flask 项目 5. 运行本地 Flask 服务 6. 启动 Ngrok 隧道并获取公网地址 7. 完整示例代码汇…...
flutter和vue3项目利用webview_flutter插件通信
近来需要实现一个功能: flutter项目的会员中心页面跳转到vue3项目的活动页,点击该活动页面的“签到”按钮后到flutter项目的积分中心页面进行签到,签到成功后手动返回上一个页面即vue3活动页面的按钮状态更新问题(需更新为“已签到”)。 实现方法:通过webview_flutter …...
sql 根据时间范围获取每日,每月,年月的模版数据
1:获取每日模版数据(参数也支持跨年) SELECT a.selected_date cdate FROM(SELECT adddate(1970-01-01,t4.i * 10000 t3.i * 1000 t2.i * 100 t1.i * 10 t0.i) selected_dateFROM( SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELEC…...
亚信安全与联通数科达成战略合作,成立联信事业部
4月22日,亚信安全与联通数字科技有限公司(以下简称“联通数科”)正式签署战略合作协议,双方宣布将联合成立“联信事业部”,仪式上,联通数科董事长孙江山与亚信安全董事长何政为“联信事业部”成立揭牌&…...
第五节:进阶特性高频题-Teleport与Suspense组件应用
Teleport:解决模态框/弹窗的DOM层级问题(如挂载到body) Suspense:处理异步组件加载状态(fallback内容展示) 深入解析 Vue3 的 Teleport 与 Suspense 组件 一、Teleport 组件:突破 DOM 层级限制…...
如何使用 uv 构建 Python 包并本地安装
本文将逐步指导你创建一个简单的 Python 包,并将其本地安装到机器或云环境中。完成本教程后,你将拥有一个可复用的 Python 库,可直接通过 pip 安装或在项目中导入使用。 步骤详解 Step 0: 选择构建工具 - 使用 uv 推荐理由:uv 是…...
集结号海螺捕鱼组件搭建教程与源码结构详解(第一篇)
本系列将基于 C Unity3D Java MySQL 构建的集结号海螺捕鱼平台,全面拆解组件架构、服务部署、客户端接入、数据库结构等内容,适合技术团队二次开发及运维部署。 一、整体架构说明 集结号海螺捕鱼平台采用三层结构: 客户端(Uni…...
RabbitMQ复习笔记
文章目录 MQ 概述同步调用拓展性差的问题性能下降的问题级联失败问题 异步调用举例 技术选型 RabbitMQRabbitMQ 安装RabbitMQ 收发消息交换机队列绑定关系模拟发送消息 RabbitMQ 数据隔离用户管理virtual host 授权 SpringAMOPSpringAMOP 快速入门消息发送消息接收 Work Queues…...
游戏开发核心技术解析——从引擎架构到攻防体系的完整技能树
游戏开发必备的7大技术体系,涵盖从Unity/Unreal引擎应用、C/C#编程范式到图形渲染管线构建等核心技术,特别剖析MMO游戏开发中的网络安全架构设计要点。通过2023年某头部游戏公司DDoS攻击事件,揭示实时防御策略与合规审计的关键作用。一、游戏…...
Execl 最佳字体和大小推荐[特殊字符]
文章目录 ✅ **通用推荐字体与字号**🔤 **字体说明**📊 场景推荐📁 办公文档(如财务报表、周报等)📈 数据可视表格📋 打印友好 🌐 多语言场景(中英文混排) ✅…...
JavaScript学习教程,从入门到精通,Ajax与Node.js Web服务器开发全面指南(24)
Ajax与Node.js Web服务器开发全面指南 一、初识Ajax 1.1 Ajax基本概念 语法知识点: Ajax (Asynchronous JavaScript and XML) 是一种无需重新加载整个网页的情况下,能够更新部分网页的技术核心对象:XMLHttpRequest工作原理: 创…...
VR 全景看车的独特优势
全方位沉浸式体验 VR 全景看车最显著的优势,就是为用户带来了全方位的沉浸式体验。通过 VR 技术,用户仿佛置身于真实的汽车展厅或试驾场景之中,能够 360 度无死角地观察车辆的外观、内饰、细节等各个方面 。无论是车辆的整体造型࿰…...
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
先说结论: ✅ 高阶函数既可以用 Lambda 表达式,也可以用函数引用! 在 Kotlin 中,高阶函数(Higher-Order Function)和 Lambda 表达式密切相关,但它们是两个不同的概念: ✅ 简单理解…...
SQL技术终极指南:从内核原理到超大规模应用
一、DDL核心应用场景与最佳实践 1.1 表结构设计场景矩阵 业务场景核心语法要素典型实现案例电商用户画像JSON字段虚拟列索引CREATE TABLE users (id INT, profile JSON, AS (profile->>$.age) VIRTUAL, INDEX idx_age((profile->>$.age)))物联网时序数据分区表压…...
Qt实现语言切换的完整方案
在Qt中实现语言动态切换需要以下几个关键步骤,我将提供一个完整的实现方案: 一、准备工作 在代码中使用tr()标记所有需要翻译的字符串 cpp button->setText(tr("Submit")); 创建翻译文件 在.pro文件中添加: qmake TRANSLATION…...
消息中间件RabbitMQ02:账号的注册、点对点推送信息
一、默认用户登录和账号注册 1.登录 安装好了RMQ之后,我们可以访问如下地址: RabbitMQ Management 输入默认的管理员密码,4.1.0的管理员账号和密码是: guest guest 2.添加账号 consumer consumer 添加成功后: 角色…...
php 支付宝官方 Alipay Easy SDK
使用 Alipay Easy SDK。 打造最好用的支付宝开放平台服务端SDK,Alipay Easy SDK让您享受极简编程体验,快速访问支付宝开放平台开放的各项核心能力。 要求: PHP版本 > 7.0安装PHP cURL扩展安装PHP OpenSSL扩展安装PHP fileinfo扩展 使用…...
深入理解 java synchronized 关键字
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
即时角色:使用可扩展的扩散变换器框架个性化任何角色
Paper Title: InstantCharacter: Personalize Any Characters with a Scalable Diffusion Transformer Framework 论文发布于2025年4月16日 Abstract部分 U-Net架构的局限性:传统的基于U-Net架构的定制方法存在一些问题,如泛化能力不足和生成图像质量的损失。 U-Net模型需要…...
开源作业调度框架Quartz框架详细使用说明
Quartz框架详细使用说明 Quartz 是一个功能强大的开源作业调度框架,广泛用于在Java应用程序中执行定时任务。以下是Quartz框架的详细使用说明、完整代码示例、同类框架对比以及总结表格。 1. Quartz框架概述 特点: 灵活的调度:支持多种调度方…...
配置Spark历史服务器,轻松查看任务记录
在大数据处理中,Spark是一个强大的分布式计算框架。但当Spark服务重启后,之前的运行记录就会消失,给我们排查问题和分析任务执行情况带来不便。这时,配置Spark历史服务器就显得尤为重要,它能帮助我们保存和查看历史任务…...
身份证实名认证:通往数字安全与便捷生活的钥匙
在数字化日益深入我们生活的今天,信息安全和隐私保护成为了每个人关心的焦点。而身份证实名认证作为保障个人信息安全的重要环节,正扮演着越来越关键的角色。它不仅是连接现实世界与数字世界的桥梁,更是确保个人在线活动安全、可靠的基础。 什…...
0基础可以考MySQL OCP么?备考时间需要多久?
最近被问爆的 “0 基础能不能考 MySQL OCP”“备考要多久” 终于来答疑啦!作为过来人,负责任地说:0 基础完全能冲! 0 基础真的能考 MySQL OCP? 很多姐妹担心自己是数据库小白,连 SQL 都没摸过,…...
node.js 实战——(概念以及Buffer 知识点学习)
概念 node.js是一个开源的、跨平台的javascript运行环境;它可以开发服务器应用,可以开发工具类应用(webpack、vite、Babel),也可以开发桌面端应用(vscode、Figma、Postman) #mermaid-svg-0TkAt8LEFhyrVrsw {font-fami…...
论文阅读 | 大模型工具调用控制的策略优化
文章目录 I. 背景II. 方法细节2.1 问题定义2.2 工具集成RL2.3 PPO2.4 GRPO2.5 OTC-PO2.5.1 OTC-PPO2.5.2 OTC-GRPO2.5.3 工具集成奖励设计 III. 实验 题目: OTC: Optimal Tool Calls via Reinforcement Learning 论文地址: OTC: Optimal Tool Calls via…...