ASCII Validation: Pessimistic vs Optimistic

Performance SIMD Optimization Benchmark ⭐⭐⭐⭐ (4星)
核心发现: ASCII 验证的"乐观"方法比"悲观"方法快 7 倍!选择取决于你的数据分布假设。

两种验证策略

悲观方法 (Pessimistic)

假设字符串可能包含非 ASCII 字符,一旦发现立即返回:

bool is_ascii_pessimistic(const char *data, size_t length) {
    for (size_t i = 0; i < length; i++) {
        if (static_cast(data[i]) > 0x7F) {
            return false;
        }
    }
    return true;
}

乐观方法 (Optimistic)

假设字符串是纯 ASCII,使用位运算 OR 减少分支:

bool is_ascii_optimistic(const char *data, size_t length) {
    unsigned char result = 0;
    for (size_t i = 0; i < length; i++) {
        result |= static_cast(data[i]);
    }
    return result <= 0x7F;
}

性能对比 (Intel Ice Lake, GCC 15)

方法 速度
悲观 (标量) 1.8 GB/s
乐观 (标量) 13 GB/s
悲观 (simdutf 库) 14 GB/s
差异: 乐观方法比悲观方法快 7 倍

为什么乐观方法更快?

  • 编译器优化: 乐观方法更容易被编译器自动向量化 (SIMD)
  • 减少分支: 不需要条件分支,CPU 流水线更顺畅
  • 内存带宽: 现代 CPU 受内存带宽限制,减少分支意味着更少的预测失误

如何选择?

场景 推荐方法
数据通常包含非 ASCII 悲观 (尽早退出)
数据几乎总是 ASCII 乐观 (最快)
需要两者兼顾 simdutf 库 (14 GB/s)

高级方案:simdutf 库

如果想要"悲观"的早期退出特性,又想要高性能,可以使用 simdutf 库的 validate_ascii_with_errors 函数:

  • 自动选择最佳策略
  • 手动优化的 SIMD 实现
  • 速度与乐观方法相当 (14 GB/s)

启示

  1. 没有银弹: 最佳方法取决于数据分布
  2. 编译器很聪明: 给编译器优化的机会,它可能做得比你好
  3. 库是朋友: 专业库 (如 simdutf) 可以结合最佳策略
  4. 测试真实数据: 基准测试必须在真实数据上运行

来源: Daniel Lemire's Blog