C++ 库长期以来一直围绕流类进行组织,至少在读取和解析字符串方面是如此。但流可能会慢得惊人。例如,如果您想解析数字,那么这个 C++ 例程几乎是性能最差的选择:
std :: stringstream in ( mystring ) ; 而(在>> x ) { 总和+ = x ; } 返回总和;
我最近了解到,出于性能原因,一些 Node.js 工程师在构建字符串时更喜欢流类。我对此表示怀疑。
让我们来做一个实验。我们将采用包含“%”字符的字符串,并构建新字符串,其中“%”字符被“%25”替换,但字符串的其余部分保持不变。
直接的字符串构造如下:
std ::字符串 string_escape ( const std :: string_view文件路径) { std ::字符串转义文件路径; for ( size_t i = 0 ; i <文件路径.length ( ) ; ++ i ) { escaped_file_path += file_path [ i ] ; if (文件路径[ i ] == ' % ' ) escaped_file_path += " 25 " ; } 返回转义文件路径; }
使用流的优化版本如下:
std :: stringstream_escape ( conststd :: string_view 文件路径) { std :: ostringstream escaped_file_path ; for ( size_t i = 0 ; i <文件路径.length ( ) ; ++ i ) { escaped_file_path << file_path [ i ] ; if (文件路径[ i ] == ' % ' ) escaped_file_path << " 25 " ; } 返回escaped_file_path 。 str ( ) ; }
我设想在包含很少“%”字符的字符串上使用这些函数。大多数字符串可能不包含“%”。在这种情况下,我可以只搜索该角色,并且只在找到该角色后才做一些重要的工作。以下代码应该执行以下操作:
std :: string find_string_escape ( std :: string_view str ) { std ::字符串转义文件路径; size_t 位置= 0 ; while ( ( pos = str .find ( ' % ' , pos ) ) != std :: string_view :: npos ) { escaped_file_path += str 。子字符串( 0 ,位置+1 ) ; escaped_file_path += " 25 " ; str = str 。子字符串(位置+1 ) ; 位置= 0 ; } escaped_file_path += str ; 返回转义文件路径; }
我编写了一个基准测试,它使用大量实际文件 URL 集合作为数据源。该基准测试在 macOS 和 Linux 下运行。我使用 Linux、最新的 Intel 服务器和 GCC 12:
天真的字符串 | 260 纳秒/串 | 0.45GB/秒 |
溪流 | 1000 纳秒/串 | 0.12GB/秒 |
寻找 | 33 纳秒/串 | 3.49GB/秒 |
至少在这种情况下,我发现流版本比简单的字符串处理慢四倍,比优化的“查找”方法慢 30 倍。
您的结果将根据您的系统而有所不同,但我通常认为在 C++ 中使用流表明性能可能较差。
原文: https://lemire.me/blog/2023/10/19/for-processing-strings-streams-in-c-can-be-slow/