Rerun 跨进程共享录制实战:用 RecordingId 把多进程数据聚合到同一个 Recording 📅 发布时间:2026/9/17 19:25:37 👁 浏览次数: Rerun 跨进程共享录制实战用 RecordingId 把多进程数据聚合到同一个 Recording【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun导读在机器人、多传感器或多 Agent 系统中数据往往由多个进程甚至多台机器同时产生逐个进程查看数据既割裂又低效。Rerun 官方 Rust 示例shared_recording展示了解决该问题的核心思路通过显式指定RecordingId让多个独立进程向同一个 Recording 追加数据。本文以该示例为骨架结合 Rerun 仓库中RecordingStreamBuilder与RecordingId的源码实现深入讲解共享录制的原理、正确用法与注意事项读完你可以在自己的多进程应用中落地“一次启动 Viewer、多进程并发灌数据”的可视化方案。示例概览一份把数据“写进同一个文件”的日志程序示例位于 examples/rust/shared_recording仓库内包含三个文件README.md——示例说明文档src/main.rs——核心演示代码仅 14 行Cargo.toml——依赖声明通过rerun { path ../../../crates/top/rerun }直接引用仓库内的 crates/top/rerun crate。README 给出了最直接的验证方式多次执行cargo run每次执行都会向已有的 recording 追加数据而不是新建一个 recordingcargo run从源码结构看这个示例在 examples/manifest.toml 体系下属于 Rust 官方示例集合的一部分适合作为多进程日志聚合的最小复现起点。需要注意的是示例依赖仓库内的reruncrate 路径直接cargo run前请先确认当前环境满足 BUILD.md 中描述的工具链要求示例 Cargo.toml 声明rust-version 1.96、edition 2024。逐行拆解main.rs 中的共享录制三要素src/main.rs 的完整代码如下//! Demonstrates how to use RecordingIds to build a single recording from multiple processes. fn main() - Result(), Boxdyn std::error::Error { let rec rerun::RecordingStreamBuilder::new(rerun_example_shared_recording) .recording_id(my_shared_recording) .spawn()?; rec.log( updates, rerun::TextLog::new(format!(hello from process #{}, std::process::id())), )?; Ok(()) }这段代码隐藏了三个决定共享行为的关键要素应用标识ApplicationIdRecordingStreamBuilder::new(rerun_example_shared_recording)中的字符串是ApplicationId通常取应用名。RecordingStreamBuilder::new 的文档明确说明它“通常是你的应用名”。它是定位 recording 的命名空间之一但仅靠相同的 ApplicationId 不足以共享录制。录制标识RecordingId.recording_id(my_shared_recording)是本示例的灵魂。多个进程只要传入相同的字符串作为 RecordingId就会被视为同一个 recording。输出目的地Sink.spawn()会把数据通过 gRPC 流向一个 Viewer。spawn_opts 的实现显示若目标端口上已有 Viewer 在监听数据流会被重定向到该 Viewer 而不是再启动一个新的源码注释原文“If a Rerun Viewer is already listening on this port, the stream will be redirected to that viewer instead of starting a new one”。这正是“多次运行、数据累积在同一个录制中”能够成立的传输层前提。rec.log(updates, rerun::TextLog::new(...))写入一条文本日志内容带上当前进程的 PIDstd::process::id()这样多次运行后你能在 Viewer 里清晰地区分每次调用来自哪个进程。底层原理RecordingId 到底是什么RecordingId定义在 crates/store/re_log_types/src/lib.rspub struct RecordingId(ArcString);关键设计点它是一个ArcString包装类型成本低廉、可克隆、可比较派生PartialEq、Eq、Hash等 trait因此可以作为多个进程间约定一致的标识。类型文档明确在日志 SDK 语境下它默认是一个 uuid但并不要求必须是 uuid——也可以是用户自定义的名字。本示例的my_shared_recording正是用户自定义名称的用法。提供RecordingId::random()生成形如rec_{uuid}的随机值Fromstr/FromString让任意字符串可直接转换。在 Rerun 的数据模型中RecordingId 并不是孤立的它和StoreKind、ApplicationId一起组成StoreIdcrates/store/re_log_types/src/lib.rspub struct StoreId { kind: StoreKind, application_id: ApplicationId, recording_id: RecordingId, }StoreId的Display输出格式为{kind}:{application_id}:{recording_id}。也就是说Rerun 服务端区分不同 recording 的唯一依据就是 StoreId 三元组两个进程只有 kind、application_id、recording_id 三者全部一致数据才会被合并到同一条录制里。默认行为不指定 RecordingId 会发生什么RecordingStreamBuilder的默认行为是每个进程生成一个随机 RecordingId。证据链如下结构体定义中recording_id字段类型为OptionRecordingIdnew()构造时初始化为Nonecrates/top/re_sdk/src/recording_stream.rs#L212在into_args()中StoreId 构造时使用recording_id.unwrap_or_else(RecordingId::random)crates/top/re_sdk/src/recording_stream.rs#L686-L690recording_id()方法文档也写明“默认使用随机 RecordingId”crates/top/re_sdk/src/recording_stream.rs#L284。因此若去掉.recording_id(my_shared_recording)这一行每次cargo run都会生成新的随机录制多次运行之间互不关联——这正是共享录制示例想要对比展示的“反面场景”。进阶细节共享 RecordingId 时的属性冲突与 send_properties当你让多个进程共享同一个 RecordingId 时还有一个容易被忽略的细节recording_id()的文档注释给出了明确说明crates/top/re_sdk/src/recording_stream.rs#L276-L292共享同一个 RecordingId 的进程各自会发送自己的 recording 属性properties合并时最新发送的那个会被选中如果不想这样可以使用send_properties退出该行为。对应的 API 是 send_properties/// Whether the [RecordingInfo] chunk should be sent. pub fn send_properties(mut self, should_send: bool) - Self此外RecordingStreamBuilder还提供recording_name(...)设置录制显示名与recording_started(...)设置开始时间来定制RecordingInfo。在多进程场景中如果你希望由“主进程”统一声明录制属性可以只在主进程调用这些方法并在从进程中调用.send_properties(false)避免后启动的进程覆盖掉主进程设定的录制元信息。多进程共享录制的最佳实践结合示例与源码在真实项目中落地跨进程共享录制时可以遵循以下做法约定统一的 RecordingId把 RecordingId 作为进程间约定配置文件、环境变量或命令行参数下发所有进程传入完全一致的字符串。源码层面recording_id接收impl IntoRecordingId字符串、String、SegmentId均可直接传入。同一 ApplicationId所有进程使用相同的应用名保证 StoreId 三元组一致。先启动 Viewer 或让首进程 spawnspawn()在无 Viewer 时会启动新 Viewer后续进程连接同一端口时会被重定向到已有 Viewer见上文spawn_opts的实现。也可以显式使用connect_grpc系列方法连接固定地址实现跨机器共享gRPC 传输由GrpcSink承担入口见 crates/data_flow/re_grpc_client。善用 PID 或时间戳区分来源示例用std::process::id()标记文本生产环境可以用 Agent 名、节点名等更有语义的字段作为日志内容或实体路径前缀便于在 Viewer 中快速分辨数据归属。谨慎处理录制属性若多个进程都设置了 recording 属性记住“最新覆盖”的语义不想互相覆盖时用send_properties(false)关闭。总结shared_recording示例虽然只有十几行代码却精准演示了 Rerun 多进程可视化的核心机制RecordingId 是跨进程聚合数据的关键钥匙它与 ApplicationId、StoreKind 共同构成 StoreId只有三者一致的数据才会被合并进同一条录制而spawn()对已有 Viewer 的连接重定向则为“多进程 → 单一 Viewer”提供了传输层保障。理解这两点你就掌握了在分布式日志、多智能体仿真、机器人集群等场景中构建统一可视化视图的基础能力。如果你希望进一步验证底层行为可以在 crates/top/re_sdk 中检索recording_id与RecordingStreamBuilder的相关实现与测试或对照 docs/content/concepts 中关于数据模型与 Recording 的说明加深理解。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考