同一份 Rust 代码,一边编译成 WebAssembly 在浏览器里跑,一边编译成原生程序在服务端多线程跑
cargo build --release -p computepython3 scripts/serve.py 8080 --mcp mcp.config.json --compute(pm2 的配置已经带上 --compute)两边都是单线程,运行同一份 Rust 源码、同样的优化级别(opt-level "s")。服务端的「计算耗时」由程序自己计时,「总耗时」是页面看到的整个请求(启动程序、生成输入、网络往返)。先跑浏览器、再跑服务端,免得同一台电脑上互相抢 CPU。
需要本地服务:serve.py … --mcp mcp.config.json --compute | 左侧色条:每条行带由哪个服务端线程渲染
同一份 Rust 源码可以编译成两种东西:wasm32-unknown-unknown 目标的 WebAssembly,交给浏览器执行;或者当前机器的原生程序,由操作系统直接执行。本页把 SHA-256、DEFLATE、数独求解和路径追踪这几个示例的 crate 原样编译成服务端程序 compute,和浏览器里的 wasm 跑同样的输入,比较耗时,并逐位比对结果,确认两边真的是同一份代码。
crates/native/compute 直接依赖 sha256、compress、sudoku、pathtracer 这几个示例 crate(它们因此同时编译成 cdylib 和 rlib)。两边用同样的优化级别(opt-level "s")编译,输入由同一个 xorshift32 生成器产生,所以哈希、压缩结果、数独的搜索步数都必须逐位相同,页面会检查。compute_bridge.py 把它转成服务器推送事件(SSE)发给页面,页面用 fetch 流式读取并当场画出来。左侧的色条标出每条行带由哪个线程完成,可以看到行带是乱序到达的。为什么不用 EventSource 接收?它在连接结束时会自动重连——这里等于再发起一次渲染;而且拿不到 HTTP 状态码(429 繁忙、401 未登录)。用 fetch 读流两个问题都没有。
POST /api/compute/bench;渲染:GET /api/compute/render 流式读取行带。compute bench 调用各 crate 的函数并自己计时;compute render 用标准库线程渲染行带,每条一行 JSON 写到标准输出。compute_bridge.py 校验参数、限制并发(最多 2 个)、超时后结束进程;页面关闭时也立刻结束渲染进程。pathtracer wasm,画完后和服务端的图逐像素比对。计算接口和 MCP 调试台用同一套访问控制:本机凭令牌,通过域名访问需要登录,因为它消耗的是这台机器的 CPU。
源码crates/native/compute/src/lib.rs服务端程序crates/graphics/pathtracer/src/lib.rsTracer:行带渲染scripts/compute_bridge.py参数校验、并发与超时www/server-compute/index.jswww/server-compute/render-worker.js