当性能很重要时,避免逐个字符处理

2020-07-25 11:17:35

在处理字符串时,很容易将其视为字符(或字节)数组,并将其作为字符(或字节)进行处理。

假设您想要确定字符串是否为ASCII。在ASCII中,每个字符都必须是小于128的字节值。检查字符串是否为ASCII的一个很好的C++17方法可能如下所示。

Bool is_ascii_Branch(const std::string_view v){for(size_t i=0;i<;v.size();i++){if(uint8_t(v[i])>;=128){return false;}}返回true;}。

在此代码的逻辑中考虑这一点很重要。您告诉编译器的是按顺序访问所有字符,检查它是否是ASCII字符,如果不是,则退出。因此,如果字符串不包含ASCII字符,则只应读取第一个字符。

如果您希望字符串主要以非ASCII字符开头,则它可能是高性能代码。但是,如果您期望字符串几乎总是ASCII,那么此代码将不会是最佳的。

您可能会抱怨编译器应该能够为您优化它,它确实会这样做,但只是在您提供的代码的约束范围内。编译器通常不负责重新设计算法。

如果您期待ASCII输入,那么您应该使用尽可能少的步骤来遍历字符串。以下代码依赖于这样一个事实,即我们的处理器可以使用单个指令处理64位块:

Bool is_ascii_Branch(const std::string_view v){uint64_t run=0;size_t i=0;for(;i+8<;=v.size();i+=8){uint64_t payload;memcpy(&;payload,v.data()+i,8);running|=payload;}for(;i<;v.size();I++){Running|=v[i];}return(Running&;0x8080808080808080)==0;}。

这是一个乐观的函数:如果您在早期遇到非ASCII字符,如果字符串很长,您最终会做很多不必要的工作。

你可以尝试一下这两者的混合体。你读8个字符,检查它们是否是ASCII,如果不是,就跳出来。

Bool is_ascii_hyder(const std::string_view v){size_t i=0;for(;i+8<;=v.size();i+=8){uint64_t payload;memcpy(&;payload,v.data()+i,8);if((payload&;0x808080808080808080)!=0)返回false;}for(;i<;v.size(。I++){if((v[i]&;0x80)!=0)return false;}return true;}。

这些功能如何比较?我用短的ASCII字符串(少于128个字符)编写了一个快速基准测试。我知道逐个字符的速度大约是原来的一半。您的结果各不相同,请使用您的编译器在您的机器上运行我的基准测试。

通过一些工作,您可能可以进行得更快,但请注意,我特意选择了一个带有小的、零散的字符串的基准测试。