要将 ASCII 字符串转换为整数值,您不能比atoi
正在执行的操作快得多,但您可以通过实现内联使用的转换函数来加快速度。下面的版本将指针递增超过扫描的数字,因此它与语义不匹配atoi
,但它应该有助于提高解析器效率,如下图所示。(显然缺少错误检查,所以如果需要,请添加它。)
static inline int my_parsing_atoi(const char *&s) {
if (s) {
bool neg = false;
int val = 0;
if (*s == '-') { neg = true; ++s; }
for (;isdigit(*s);++s) val = 10*val + (*s - '0');
return neg ? -val : val;
}
return 0;
}
const char *p = input_line;
if (p) {
p += strspn(p, " ");
while (*p) {
int value1 = my_parsing_atoi(p);
p += strspn(p, " ");
}
}
确保您已经正确地分析了您的代码,以便您知道您的例程受计算限制而不是 I/O 限制。大多数情况下,您会受到 I/O 限制,下面的建议是缓解这种情况的方法。
如果您正在使用 C 或 C++ 文件读取例程,例如fread
or fstream
,您应该会获得已经非常有效的缓冲读取,但您可以尝试使用底层操作系统调用(例如 POSIX read
)来读取更大块中的文件同时加快文件读取效率。真正花哨的是,您可以在处理文件时执行文件的异步读取,可以使用线程,也可以使用aio_read
. 您甚至可以使用mmap
,这将消除一些数据复制开销,但如果文件非常大,您将需要管理地图,以便您munmap
扫描文件mmap
的部分和要扫描的新部分。
我使用如下代码对上面的解析例程和 OP 的例程进行了基准测试:
clock_t before_real;
clock_t after_real;
struct tms before;
struct tms after;
std::vector<char *> numbers;
make_numbers(numbers);
before_real = times(&before);
for (int i = 0; i < numbers.size(); ++i) {
parse(numbers[i]);
}
after_real = times(&after);
std::cout << "user: " << after.tms_utime - before.tms_utime
<< std::endl;
std::cout << "real: " << after_real - before_real
<< std::endl;
和之间的区别在于real
,user
这real
是挂钟时间,user
而是操作系统运行进程所花费的实际时间(因此上下文切换不计入运行时间)。
我的测试让我的例程运行速度几乎是 OP 例程的两倍(g++ -O3
在 64 位 Linux 系统上编译)。