RustInPractice(24):SQLite 与 rusqlite
rusqlite 用 Rust 类型包装 SQLite 的连接、参数绑定、查询和事务。核心规则是:SQL 值永远通过参数绑定传递,不用字符串拼接。 对应 database/sqlite3。下一篇:数据结构。 1234conn.execute( "INSERT INTO students (class_id, name, score) VALUES (?1, ?2, ?3)", params![1, name, score],)?; query_map 将行映射为 struct,? 将数据库失败传播到调用边界。事务应使用 checked transaction,并同时演示 commit 与 rollback;当前 demo 使用内存数据库和 unchecked_transaction(),只适合作为 API 导览。 真实项目还应启用 foreign keys、维护 migration、测试约束、使用持久路径,并决定连接是否只能在同步线程中使用。 下一篇:数据结构在 Rust 中的所有权边界。
RustInPractice(23):WebSocket 与异步流
WebSocket 在 HTTP upgrade 后保持双向消息通道。tokio-tungstenite 将连接同时实现 Stream 与 Sink,接收用 next().await,发送用 send().await。 对应 networking/websocket。下一篇:SQLite。 1234while let Some(message) = ws.next().await { let message = message?; ws.send(Message::Text("Echo: hello".into())).await?;} 服务端通常为每条连接 spawn 一个 task,连接结束后 task 自动结束。需要显式处理 text、binary、ping、pong、close 和错误;demo 将 binary 转成文本提示,因此它是文本 echo,不是保留二进制 payload 的 echo 服务。 accept 循环也不应静默吞掉 listener 错误。生产服务还需要连接上限、超时、认证和关闭协议。 ...
RustInPractice(22):用 Axum 写 JSON API
Axum 将路由、提取器和返回值组合成类型安全的 HTTP API。demo 用 Router、Json 和共享状态完成一个最小用户接口。 对应 networking/http_json。下一篇:WebSocket 与异步流。 路由与提取器123Router::new() .route("/users", get(list_users).post(create_user)) .route("/users/:id", get(get_user)) State(store) 取得应用状态,Path(id) 解析路径参数,Json(body) 反序列化请求体。handler 返回 Json<T>,Serde 负责序列化。 状态与错误demo 用 Arc<Mutex<HashMap<...>>> 保存内存数据,锁只在同步读取或写入期间持有,绝不能跨 .await。真实 API 应增加输入验证、201 Created、结构化错误体、稳定排序和 handler 集成测试。 这个 st...
YOLO 目标检测实战(02):预训练模型冒烟推理
目标:在正式训练之前,先用官方预训练权重对样例图跑一次检测,确认 GPU 推理链路是通的。这一步花不了几分钟,却能把「环境没配对」和「训练超参没调好」这两类问题彻底分开。 这是「YOLO 目标检测实战」的第 02 篇。完整目录见 00 · 系列导读。 一、前置条件 已完成 01 · 环境搭建; 存在预训练 s 档权重(如 weights/yolo_s.pt)与 data/images/(由 scripts/00_download_assets.sh 准备)。 二、执行容器内: 1bash scripts/01_smoke_detect.sh 等价于: 1234567yolo detect predict \ model=/workspace/weights/yolo_s.pt \ source=/workspace/data/images \ device=0 \ project=/workspace/runs/detect \ name=smoke \ exist_ok=True 三、产物可视化结果写到: 1runs/detect/smoke/ 打开...
多模态微调实战(03):从 LMDB 到 JSONL 的数据准备
多模态微调里,数据格式比模型名字更容易卡住人。ms-swift 期望的是「对话 JSONL + 图片路径」,而公开 OCR 数据集常常是 LMDB / TFRecord 等离线格式,中间需要一层转换。这一篇讲怎么把数据整理成训练框架能直接吃的样子。 这是「多模态微调实战」的第 03 篇。环境就绪后,数据是下一个门槛。 一、数据从哪来本系列任务使用 ModelScope 上的车牌 OCR 数据(公开集,示例名:ocr_plate): 完整规模大约:训练 37 万 + 验证 4 万; 原始形态多为 LMDB(图像二进制 + 标签字符串); 建议流程:先转一个小子集验证,再转全量。 二、LMDB 里大概长什么样常见键设计(示意): 123num-samples -> 样本总数image-000000001 -> 图片二进制label-000000001 -> 车牌字符串(UTF-8) 转换时要约定: 图片导出到哪里; JSONL 里写相对还是绝对路径(容器内建议统一成 /workspace/...); 用...
RustInPractice(21):CLI、配置、日志与错误边界
语言特性最终要落到程序入口。一个可靠 CLI 应将参数解析、配置读取、业务逻辑、日志和错误呈现分层,使核心代码可测试、命令行只是薄薄的一层适配器。 RustInPractice 第三季收官篇。对应 demo:learning_guide、argv_demo、filesystem_demo。第四季将进入 Axum、WebSocket、SQLite 与算法实践。 一、用 Clap 声明命令结构12345#[derive(clap::Subcommand)]enum Commands { List, Demo { name: String },} learning_guide 将 subcommand 解析后交给 demos::run。入口只负责输入适配,模块负责业务行为,这让同一逻辑既能被 CLI 调用,也能被测试直接调用。 二、配置来源要有优先级常见顺序是:命令行参数 > 环境变量 > 配置文件 > 安全默认值。不要把密钥写进默认值、示例输出或日志;示例使用 user@example.com、<T...
RustInPractice(20):限流、背压与后台任务
每个请求都 spawn 一个任务看起来很轻松,但高峰时会把内存、连接和下游服务推向失控。生产级异步系统的关键不是“能并发”,而是“知道什么时候必须慢下来”。 RustInPractice 第 20 篇。对应 demo:concurrency/thread_pool。下一篇用 CLI、配置、文件和日志组织一个真实入口。 一、demo 实际是什么?TaskPool 使用 tokio::sync::Semaphore: 12let _permit = semaphore.acquire().await?;run_task().await; 它限制同一时刻运行的任务数量,但每个提交仍会创建 Tokio task。因此它准确的名称是异步并发限制器,不是固定 worker 线程池。真正 worker pool 通常还需要有界 channel、固定 worker 集合和关闭协议。 二、背压策略必须可见队列或 semaphore 满时,系统可以: 策略 结果 等待 提高延迟,保护下游 拒绝 快速返回,调用方重试或降级 超时 避免无限等待 丢弃 只适合可丢失事件 ...
RustInPractice(19):Tokio 异步基础
async 不是“自动开线程”。Rust 的 async fn 返回 Future,Future 只有被 runtime 轮询时才推进;遇到 .await 无法继续时,它让出执行权,其他任务可以运行。 RustInPractice 第 19 篇。对应 demo:learning_guide 的 async 子命令、thread_pool。下一篇讨论有界并发与后台任务。 一、Future 是惰性的描述123async fn fetch_name() -> String { "Rust".to_string()} 调用 fetch_name() 得到的是 Future,不会立刻执行。需要在 async 上下文 .await,并由 Tokio runtime 等 executor 轮询: 12345#[tokio::main]async fn main() { let name = fetch_name().await; println!("{name}");...
RustInPractice(18):Send、Sync 与消息传递
当 Rust 拒绝把某个值送进线程时,它不是在“限制你”,而是在检查线程边界上的安全契约。Send 描述值能否转移给另一个线程,Sync 描述共享引用能否被多个线程安全访问。 RustInPractice 第 18 篇。前置:第 17 篇原生线程。下一篇进入 Tokio async。 一、两个 marker trait trait 含义 Send 类型的所有权可安全转移到另一个线程 Sync &T 可安全被多个线程共享 大多数普通值自动实现二者。Rc<T> 不是 Send,因为引用计数不是原子操作;Arc<T> 使用原子计数,因此可跨线程共享。 123let data = std::sync::Arc::new(vec![1, 2, 3]);let worker = std::sync::Arc::clone(&data);std::thread::spawn(move || println!("{:?}", worker)); 二、优先传递所有权和消息如果任务不必共同修改...
RustInPractice(17):原生线程与同步原语
Rust 消除了大量内存不安全并发,但不会自动让逻辑免于死锁、饥饿或错误同步。先理解 thread、Mutex、Condvar、Barrier 和 atomic 的职责,再决定是否需要 async。 RustInPractice 第 17 篇。对应 demo:thread_demos、sync_primitives。下一篇解释 Send、Sync 与消息传递。 一、线程必须被等待或明确放弃123let handle = std::thread::spawn(|| "worker done");let result = handle.join().expect("worker panicked");println!("{result}"); join 等待线程结束并取得结果。demo 使用 unwrap() 让学习输出简短;生产代码应决定如何处理线程 panic,而不是无条件崩溃。 二、Mutex 保护共享可变状态1234use std::sync::{Arc, Mutex}...















