经过一些性能实验后,似乎使用char16_t数组有时可以将性能提高40-50%,但似乎使用没有任何复制和分配的std::u16string应该与C数组一样快。但是,基准显示了相反的情况。

这是我为基准编写的代码(它使用Google Benchmark库):

#include "benchmark/benchmark.h"
#include <string>

static std::u16string str;
static char16_t *str2;

static void BM_Strings(benchmark::State &state) {
    while (state.KeepRunning()) {
        for (size_t i = 0; i < str.size(); i++){
            benchmark::DoNotOptimize(str[i]);
        }
    }
}

static void BM_CharArray(benchmark::State &state) {
    while (state.KeepRunning()) {
        for (size_t  i = 0; i < str.size(); i++){
            benchmark::DoNotOptimize(str2[i]);
        }
    }
}

BENCHMARK(BM_Strings);
BENCHMARK(BM_CharArray);

static void init(){
    str = u"Various applications of randomness have led to the development of several different methods ";
    str2 = (char16_t *) str.c_str();
}

int main(int argc, char** argv) {
    init();
    ::benchmark::Initialize(&argc, argv);
    ::benchmark::RunSpecifiedBenchmarks();
}

它显示以下结果:
Run on (8 X 2200 MHz CPU s)
2017-07-11 23:05:57
Benchmark             Time           CPU Iterations
---------------------------------------------------
BM_Strings         1832 ns       1830 ns     365938
BM_CharArray        928 ns        926 ns     712577

我在Mac上使用clang(Apple LLVM版本8.1.0(clang-802.0.42))。启用优化后,差距变小了,但仍然很明显:
 Benchmark             Time           CPU Iterations
---------------------------------------------------
BM_Strings          242 ns        241 ns    2906615
BM_CharArray        161 ns        161 ns    4552165

有人可以解释这里发生了什么以及为什么会有区别吗?

更新(混合顺序并添加了一些预热步骤):
Benchmark             Time           CPU Iterations
---------------------------------------------------
BM_CharArray        670 ns        665 ns     903168
BM_Strings          856 ns        854 ns     817776
BM_CharArray        166 ns        166 ns    4369997
BM_Strings          225 ns        225 ns    3149521

还包括我正在使用的编译标志:
/usr/bin/clang++ -I{some includes here} -O3 -std=c++14 -stdlib=libc++ -Wall -Wextra -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -O3 -fsanitize=address -Werror -o CMakeFiles/BenchmarkString.dir/BenchmarkString.cpp.o -c test/benchmarks/BenchmarkString.cpp

最佳答案

由于libc++实现了小型字符串优化的方式,因此在每次取消引用时,都需要检查字符串内容是存储在字符串对象本身中还是存储在堆中。因为索引是用benchmark::DoNotOptimize包装的,所以每次访问字符时都需要执行此检查。通过指针访问字符串数据时,数据始终在外部,因此无需检查。

关于c++ - 为什么std::u16string比char16_t数组慢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45043742/

10-11 22:59
查看更多