C++ 如何优化strtok+;环礁
在执行时间方面,有什么好方法可以优化此函数吗?我的最终目标是解析由几个整数组成的长字符串(每行数千个整数,数千行)。这是我最初的解决方案C++ 如何优化strtok+;环礁,c++,string,performance,optimization,C++,String,Performance,Optimization,在执行时间方面,有什么好方法可以优化此函数吗?我的最终目标是解析由几个整数组成的长字符串(每行数千个整数,数千行)。这是我最初的解决方案 int64_t get_next_int(char *newLine) { char *token=strtok(newLine, " "); if( token == NULL ) { exit(0); } return atoll(token); } 更多详细信息:我需要基于“状态”的strtok实现,因此
int64_t get_next_int(char *newLine) {
char *token=strtok(newLine, " ");
if( token == NULL ) {
exit(0);
}
return atoll(token);
}
更多详细信息:我需要基于“状态”的strtok实现,因此strtok实现的填充应该存在于最后一个字符串中。环礁不需要任何形式的核查
/*
* 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;
}
目标系统:英特尔x86_64(至强系列)
相关主题:
- atoi优化:
- 我宁愿使用类似于
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()
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;
int n=0;
//找到代币
对于(;*换行符=='';换行符++)
;
如果(*换行符==0)
//找不到
出口(0);
//扫描并转换令牌
对于(;无符号(*换行符-'0')<10;换行符++)
n=10*n+*换行符-'0';
返回n;
我从您的代码中获得的AFA在第一次拆分时将返回。似乎在第一次解析时(在空格字符之前),如果它是非数字条目,或者是字母和数字的组合,那么它将返回0,以使字母在开头。如果在开始时与number组合,它将仅返回数字。也就是说,转换只需要一个字符串。因此,您不需要标记化,只需检查字符串是否为null即可。您还可以更改退货类型。因为,如果您需要一个具有64位的类型,请使用(u)int64_t
,如果您至少需要64位,(无符号)long long
是非常好的,就像(u)int\u t
一样。我觉得你的代码有点胡说八道。展示你想要的东西,不要简单化
/*
* 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;
}
首先:我发现优化信号处理链中的字符串转换例程在大多数情况下都是徒劳的。系统以字符串形式加载数据的速度(这可能会发生在某些大容量存储中,它是由一些不关心性能的东西放置的,因为它本来不会选择字符串格式,否则),如果将通过PCIe连接的SSD集群以外的所有SSD的读取速度与atoll
的速度进行比较,您会注意到在低效转换上损失的时间可以忽略不计。如果通过转换以管道方式加载该字符串的一部分,则等待存储所花费的时间甚至不会被远程转换所填满,因此,即使没有任何算法优化,管道化/多线程也将消除几乎所有用于转换的时间
我将继续假设包含字符串的整数足够大。比如,数千万个整数。否则,考虑到没有什么可抱怨的,所有的优化都可能是相当不成熟的
现在,诀窍是,一旦转换例程的性能达到内存带宽障碍,就无法进行性能优化。为了尽可能地克服这一障碍,优化CPU缓存的使用至关重要——因此,尽可能少地进行线性访问和洗牌内存在这里至关重要。此外,如果您关心速度,那么您不希望每次需要转换几个数字时都调用函数——调用开销(保存/恢复堆栈、来回跳转)将非常大。因此,如果您关注性能,您将立即对整个字符串进行转换,然后只访问生成的整数数组
因此,在一个现代的、支持SSE4.2的x86处理器上,您大概有点像
外环,以16步跳转:
- 将128位输入字符串加载到128位SIMD寄存器中
- 运行类似这样的操作,一次在所有这16个字节中查找
分隔符和\0
终止符的索引
- 找到的索引上的内循环
- 使用SSE copy/shift/immediate指令隔离子字符串;用
0
- 预结束上一次迭代中保存的“最后一个字符”(如果有–仅适用于每个外循环迭代的第一次内循环迭代)
- 从每个数字中减去
0
,再次使用SSE指令对单个指令进行最多16次减法()
- 将八个16位子字转换为八个128位字,每个字包含两个压缩的64位整数(我想每16位一条指令,
\u mm\u cvtepi8\u epi64
)
- 用
[10^15 10^14]
初始化\uuu mm128
寄存器,我们称之为powers
- 循环对双64位字:(每个步骤应为一条SSE指令)
- 先乘以
幂
- 将幂除以
[100]
- 将秒乘以幂
将结果添加到双64位累加器
将累加器中的两个值相加
将结果存储到整数数组中
strtok()
有严重的缺点,不要使用它。按什么标准进行优化?美女内存带宽?内存使用情况?什么机器的速度?不清楚。好多了,谢谢!似乎在第一次解析时(在空格字符之前),如果它是非数字条目,或者是字母和数字的组合,那么它将返回0,以使字母在开头。如果在开始时与number组合,它将仅返回数字。所以,这对我来说不安全。如果没有安全性,就不应该对其进行优化。您可能希望用文字说明您试图实现的目标。strtok
(将\0
字节填入输入字符串的某个位置)的副作用是否可取?出现错误时,atol
的行为是否可取?您是否希望在发生错误时有任何特定的行为?此外,您的问题还链接到一个非常类似的问题和答案。Y