有没有什么好方法可以在执行时间方面优化此功能?我的最终目标是解析由几个整数组成的长字符串(每行数千个整数,数千行)。这是我最初的解决方案。
int64_t get_next_int(char *newLine) {
char *token=strtok(newLine, " ");
if( token == NULL ) {
exit(0);
}
return atoll(token);
}
更多细节:我需要基于“状态”的strtok实现,因此strtok实现的填充应存在于最终字符串中。环礁不需要任何形式的验证。
目标系统:Intel x86_64(Xeon系列)
相关主题:
答案 0 :(得分:2)
我宁愿使用std::istringstream
:
int64_t get_next_int(std::istringstream& line) {
int64_t token;
if(!(line >> token))
exit(0);
return token;
}
std::istringstream line(newLine);
int64_t i = get_next_int(line);
strtok()
众所周知drawbacks,您根本不想使用它。
答案 1 :(得分:2)
首先关闭:我发现信号处理链中的优化字符串转换例程大部分时间都是徒劳的。系统以字符串形式加载数据的速度(这可能发生在某些大容量存储中,而这些存储是由不关心性能的东西放置的,因为它不会选择字符串格式第一个地方,否则),如果你比较通过PCIe连接的所有SSD集群的读取速度和atoll
的速度,你会注意到你失去的时间可以忽略不计转换效率低下。如果您通过转换管道加载该字符串的部分,那么等待存储所花费的时间甚至不会被转换远程填充,因此即使没有任何算法优化,流水线操作/多线程也几乎可以消除所有转换时间。
我将继续并假设您的包含整数的字符串足够大。就像,数以千万计的整数。否则,所有优化都可能还为时过早,因为我们很少抱怨std::iostream
performance。
现在,诀窍是,一旦转换例程的性能达到内存带宽障碍,就无法进行性能优化。为了尽可能地推动这一障碍,优化CPU缓存的使用至关重要 - 因此,尽可能少地进行线性访问和重排内存至关重要。此外,如果你关心速度,你不想在每次需要转换几位数时调用一个函数 - 调用开销(保存/恢复堆栈,来回跳转)将是重要的。因此,如果您在演出结束后,您将立即转换整个字符串,然后只访问生成的整数数组。
所以你在现代的支持SSE4.2的x86处理器上有类似的东西
外循环,以16的步长跳跃:
__mm_cmpestri
的内容,一次性查找所有这16个字节中
分隔符和\0
终结符的索引0
0
,再次使用SSE指令通过一条指令进行最多16次减法(_mm_sub_epi8
)_mm_cvtepi8_epi64
,我认为)__mm128
初始化[10^15 10^14]
注册,让我们将其称为powers
powers
[100 100]
powers
store
结果为整数数组答案 2 :(得分:1)
怎么样?
int n= 0;
// Find the token
for ( ; *newline == ' '; newline++)
;
if (*newline == 0)
// Not found
exit(0);
// Scan and convert the token
for ( ; unsigned(*newline - '0') < 10; newline++)
n= 10 * n + *newline - '0';
return n;
答案 3 :(得分:1)
AFA我首先从您的代码中获取它将返回。它似乎在第一次解析时(在空格字符之前),如果它是非数字输入或者以字母开头的方式组合字母和数字,它将返回0。如果在开头合并并且数字,它将仅返回数字。也就是说,您只需要一个字符串进行转换。因此,您不需要进行标记,只需检查string
是否为空。您也可以更改返回类型。因为,如果你需要一个_exactly_64位的类型,使用(u)int64_t
,如果你需要_at至64位,(unsigned) long long
完全没问题,(u)int_least64_t
。我认为你的代码很少gobbledygook。在没有简化的情况下显示您想要的内容。
/*
* ascii-to-longlong conversion
*
* no error checking; assumes decimal digits
*
* efficient conversion:
* start with value = 0
* then, starting at first character, repeat the following
* until the end of the string:
*
* new value = (10 * (old value)) + decimal value of next character
*
*/
long long my_atoll(char *instr)
{
if(str[0] == '\0')
return -1;
long long retval;
int i;
retval = 0;
for (; *instr; instr++) {
retval = 10*retval + (*instr - '0');
}
return retval;
}