SQLite扩展C与Rust性能对比
parse_number() as a SQLite extension: C vs Rust
四个SQLite扩展用C和Rust实现相同的`parse_number()`行为,测试覆盖类型保留、解析规则和浮点精度,优化C实现每行16–19纳秒最快,约是Rust版本的两倍,远超SQL `replace()`
研究 parse_number() 作为 SQLite 扩展:C 与 Rust — 四个 SQLite 扩展在 C 和 Rust 中实现了相同的 `parse_number()` 行为,测试覆盖了类型保持、解析规则和浮点精度。优化的 C 实现最快,每行 16–19 ns,比 Rust 版本快约两倍,远快于 SQL `replace()`。纯 C 在小数上较慢,因为它依赖 `strtod()`,而一个紧凑的快速路径缩小了这一差距;所有版本在 800 万次模糊测试中表现一致。
我正在遛狗时,好奇编写一个 SQLite C 扩展来添加一个 parse_number() 函数,将 -$1,234.56 或 '12.5%' 这样的字符串转换为可求和和排序的数值,会容易还是困难.
我启动了常规的 Claude 聊天(Opus 5.5) 并提示:
I'm thinking about a SQLite custom function 'parse_number(value)' that strips ',', '$', '£' and '%', handles a leading '-', and returns 'NULL' for anything it can’t parse
Explore the difference between building this as a SQLite extension in C v.s. in Rust - I want to compare performance and code complexity and size of the resulting.so(or whatever) file
这给了我一个坚实的基础——使用 Rusqlite 的 Rust 扩展是 321 KB,使用 sqlite-loadable-rs 的是 298 KB,而 C 扩展只有 14 KB。但 Rust 扩展更快!
原来是因为 Rust 中 C 的 strtod 的等效版本 "快两倍"。所以我提示:
Try writing your own C function for parsing text into a decimal number that catches up to or beats the Rust implementation
它做到了:
超过 200 万行每行的净成本,越低越好:
first C new C rusqlite sqlite-loadable 混合数据 67 ns 19 ns 46 ns 41 ns 仅整数 25 ns 16 ns 36 ns 32 ns 仅小数 106 ns 18 ns 55 ns 47 ns
最后,我让它将原型改写为研究报告,以匹配 simonw/research 中的其他报告,提示如下:
Clone simonw/research from GitHub and turn your above investigation into a research report as seen in that repository - you can give me a zip file to download that contains your new folder
这是 生成的报告。
来源:Simon Willison · simonwillison.net