当输入缓冲区是一个非常大的字符时,std::stoul() 需要很长时间*

nga*_*yan 0 c++ performance

我有一个大小为 1024^3 (1G) 的 char* buf。它包含换行符分隔的十六进制数字 ( 7fefdfff7\n7fefdfff8\n7fefdfff9\n7fefdfff\n7fefdfffb),我正在尝试读取和解析它们中的每一个。

我的第一种方法是:

int buf_length = 1024 * 1024 * 1024;
char *buf = new char[buf_length];
std::size_t numchars = 0;
for (int offset = 0; offset <buf_length; offset += numchars) {
        unsigned long tmp = std::stoul(&buf[offset], &numchars, 16);
        process(tmp);
}
Run Code Online (Sandbox Code Playgroud)

但是循环的每次迭代都花费了异常长的时间。一旦我切换到以下内容,它的速度要快得多:

int buf_length = 1024 * 1024 * 1024;
char *buf = new char[buf_length];
std::size_t numchars = 0;
for (int offset = 0; offset <buf_length; offset += numchars) {
// omitting size of the string below does not affect performance much
        std::string s(buf, 9);
        unsigned long tmp = std::stoul(s, &numchars, 16);
        process(tmp);
}
Run Code Online (Sandbox Code Playgroud)

似乎在第一种情况下 stoul() 每次都处理到缓冲区结束,但无法解释原因。你能帮我理解这里发生了什么,为什么两种情况下的性能如此不同?

Art*_*yer 5

std::stoul需要一个const std::string&而不是一个const char*。这意味着 astd::string是从以空字符结尾的字符串构造的,需要复制每个字符。

您可以改为使用std::strtoulwhichconst char*直接接受参数:

for (const char* ptr = buf; ptr < buf + buf_length;) {
    unsigned long tmp = std::stroul(ptr, &ptr, 16);
    process(tmp);
}
Run Code Online (Sandbox Code Playgroud)