- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的程序的输入是一个很大的字符串,大约有 30,000 个字符。下面是我自己的 strlen 的代码:
size_t strlen(const char *c)
{
int i;
i = 0;
while (c[i] != '\0')
i++;
return (i);
}
上面的 strlen 版本执行大约需要 2.1 秒。通过不同的版本,我能够达到约 1.4 秒。
我的问题是,为什么多个 if 语句比执行 while 循环更快?
size_t strlen(const char *str)
{
const char *start;
start = str;
while (1)
{
if (str[0] == '\0')
return (str - start);
if (str[1] == '\0')
return (str - start + 1);
if (str[2] == '\0')
return (str - start + 2);
if (str[3] == '\0')
return (str - start + 3);
if (str[4] == '\0')
return (str - start + 4);
if (str[5] == '\0')
return (str - start + 5);
if (str[6] == '\0')
return (str - start + 6);
if (str[7] == '\0')
return (str - start + 7);
if (str[8] == '\0')
return (str - start + 8);
str += 9; //
}
}
我的问题是,为什么这么多 if 语句比仍然运行循环更快?
编辑:使用标准库,大约需要 1.25 秒。
最佳答案
您的问题是相关的,但您的基准测试不完整并且结果令人惊讶。
这是代码的修改和检测版本:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#define VERSION 3
#define TRIALS 100
#define ITERATIONS 100
#if VERSION == 1
size_t strlen1(const char *c) {
size_t i;
i = 0;
while (c[i] != '\0')
i++;
return (i);
}
#define strlen(s) strlen1(s)
#elif VERSION == 2
size_t strlen2(const char *str) {
const char *start;
start = str;
while (1) {
if (str[0] == '\0')
return (str - start);
if (str[1] == '\0')
return (str - start + 1);
if (str[2] == '\0')
return (str - start + 2);
if (str[3] == '\0')
return (str - start + 3);
if (str[4] == '\0')
return (str - start + 4);
if (str[5] == '\0')
return (str - start + 5);
if (str[6] == '\0')
return (str - start + 6);
if (str[7] == '\0')
return (str - start + 7);
if (str[8] == '\0')
return (str - start + 8);
str += 9;
}
}
#define strlen(s) strlen2(s)
#elif VERSION == 3
size_t strlen3(const char *str) {
const uint64_t *px, sub = 0x0101010101010101, mask = 0x8080808080808080;
const char *p;
for (p = str; (uintptr_t)p & 7; p++) {
if (!*p)
return p - str;
}
for (px = (const uint64_t *)(uintptr_t)p;;) {
uint64_t x = *px++;
if (((x - sub) & ~x) & mask)
break;
}
for (p = (const char *)(px - 1); *p; p++)
continue;
return p - str;
}
#define strlen(s) strlen3(s)
#endif
int get_next_line(int fd, char **pp) {
char buf[32768];
char *line = NULL, *new_line;
char *p;
ssize_t line_size = 0;
ssize_t nread, chunk;
while ((nread = read(fd, buf, sizeof buf)) > 0) {
p = memchr(buf, '\n', nread);
chunk = (p == NULL) ? nread : p - buf;
new_line = realloc(line, line_size + chunk + 1);
if (!new_line) {
free(line);
*pp = NULL;
return 0;
}
line = new_line;
memcpy(line + line_size, buf, chunk);
line_size += chunk;
line[line_size] = '\0';
if (p != NULL) {
lseek(fd, chunk + 1 - nread, SEEK_CUR);
break;
}
}
*pp = line;
return line != NULL;
}
int main() {
char *line = NULL;
int fd, fd2, count, trial;
clock_t min_clock = 0;
fd = open("one_big_fat_line.txt", O_RDONLY);
if (fd < 0) {
printf("cannot open one_big_fat_line.txt\n");
return 1;
}
fd2 = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
if (fd2 < 0) {
printf("cannot open output.txt\n");
return 1;
}
for (trial = 0; trial < TRIALS; trial++) {
clock_t t = clock();
for (count = 0; count < ITERATIONS; count++) {
lseek(fd, 0L, SEEK_SET);
lseek(fd2, 0L, SEEK_SET);
while (get_next_line(fd, &line) == 1) {
write(fd2, line, strlen(line));
write(fd2, "\n", 1);
free(line);
}
}
t = clock() - t;
if (min_clock == 0 || min_clock > t)
min_clock = t;
}
close(fd);
close(fd2);
double time_taken = (double)min_clock / CLOCKS_PER_SEC;
printf("Version %d time: %.3f microseconds\n", VERSION, time_taken * 1000000 / ITERATIONS);
return 0;
}
程序打开一个文件,使用自定义函数从中读取行 read_next_line()
使用 UNIX 系统调用和 malloc
返回任意大小的行。然后它使用 unix 系统调用 write
写入这些行。并通过单独的系统调用附加换行符。
使用您的测试文件(一个包含单行 ASCII 字符的 30000 字节文件)对该序列进行基准测试,显示出与您测量的结果截然不同的性能:取决于所选的 strlen
实现以及编译优化设置,我的笔记本电脑上每次迭代的时间范围从 15 微秒到 82 微秒,远不及您观察到的 1 或 2 秒。
使用 C 库默认实现,无论是否进行优化,每次迭代的时间都是 14.5 微秒。
使用您的strlen1
天真的实现,禁用优化时我得到 82 微秒,-O3
时我得到 25 微秒。优化。
使用您的strlen2
展开实现,速度提高到 30 微秒 -O0
和 20 微秒 -O3
.
最后,更高级的 C 实现一次读取 8 个字节 strlen3
-O0
在 21 微秒内提供进一步改进的性能和 15.5 微秒 -O3
.
请注意编译器优化对性能的影响远大于手动优化。
展开版本性能更好的原因是生成的代码每个字节递增一次指针,并且每个字节执行一次无条件跳转,而展开版本将这些减少到每 9 个字节一次。但请注意,C 编译器获得与 -O3
几乎相同的性能。简单的代码就像你自己展开循环一样。
高级版本在性能上非常接近C库实现,它可以使用带有SIMD指令的汇编语言。它一次读取 8 个字节,并执行算术技巧来检测这些字节中是否有任何字节的最高位从 0
更改。至1
当减去1
时从它的值(value)来看。需要额外的初始步骤来对齐指针以读取 64 位字,从而避免在某些体系结构上具有未定义行为的未对齐读取。它还假设内存保护在字节级别不可用。在现代 x86 系统上,内存保护具有 4K 或更大的粒度,但其他一些系统(例如 Windows 2.x)的保护粒度要细得多,完全阻止了这种优化。
但请注意,基准测试还测量从输入文件读取、找到换行符并写入输出文件的时间。 strlen
的相对表现和strlen3
可能更重要。事实上,一个单独的基准只是 strlen(line)
30000 字节行显示 strlen3()
的时间为 2.2 微秒strlen()
为 0.85 微秒.
结论:
-O3
是一个很好的默认值。关于c - 为什么多个 if 语句比执行 while 循环更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55295147/
创建一个“海盗对话”,可以选择左手或右手。我希望它对“左”和“右”的不同拼写做出积极的回答(正如您将在代码中看到的那样),但是,当我为所有非“右”或“左”的输入添加最终的“else”代码时,它给了我一
With 语句 对一个对象执行一系列的语句。 With object statements End With 参数 object 必需的部分
While...Wend 语句 当指定的条件为 True 时,执行一系列的语句。 While condition  ; Version [stat
所以我正在处理的代码有一个小问题。 while True: r = input("Line: ") n = r.split() if r == " ":
我有一个对象数组: var contacts = [ { "firstName": "Akira", "lastName": "Laine", "number"
int main() { int f=fun(); ... } int fun() { return 1; return 2; } 在上面的程序中,当从main函数中调用一个
我的项目中有很多 if 语句、嵌套 if 语句和 if-else 语句,我正在考虑将它们更改为 switch 语句。其中一些将具有嵌套的 switch 语句。我知道就编译而言,switch 语句通常更
Rem 语句 包含程序中的解释性注释。 Rem comment 或 ' comment comment 参数是需要包含的注释文本。在 Rem 关键字和 comment 之间应有一个空格。
ReDim 语句 在过程级中声明动态数组变量并分配或重新分配存储空间。 ReDim [Preserve] varname(subscripts) [, varname(subscripts)]
Randomize 语句 初始化随机数生成器。 Randomize [number] number 参数可以是任何有效的数值表达式。 说明 Randomize 使用 number 参数初始
Public 语句 定义公有变量并分配存储空间。在 Class 块中定义私有变量。 Public varname[([subscripts])][, varname[([subscripts])
Sub 语句 声明 Sub 过程的名称、参数以及构成其主体的代码。 [Public [Default]| Private] Sub name [( arglist )]
Set 语句 将对象引用赋给一个variable或property,或者将对象引用与事件关联。 Set objectvar = {objectexpression | New classname
我有这个代码块,有时第一个 if 语句先运行,有时第二个 if 语句先运行。我不确定为什么会这样,因为我认为 javascript 是同步的。 for (let i = 0; i < dataObje
这是一个 javascript 代码,我想把它写成这样:如果此人回答是,则回复“那很酷”,如果此人回答否,则回复“我会让你开心”,如果此人回答的问题包含"is"或“否”,请说“仅键入”是或否,没有任何
这是我的任务,我尝试仅使用简短的 if 语句来完成此任务,我得到的唯一错误是使用“(0.5<=ratio<2 )”,除此之外,构造正确吗? Scanner scn = new Scanner(
有没有办法在 select 语句中使用 if 语句? 我不能在这个中使用 Case 语句。实际上我正在使用 iReport 并且我有一个参数。我想要做的是,如果用户没有输入某个参数,它将选择所有实例。
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: If vs. Switch Speed 我将以 C++ 为例,但我要问的问题不是针对特定语言的。我的意思是一
Property Set 语句 在 Class 块中,声明名称、参数和代码,这些构成了将引用设置到对象的 Property 过程的主体。 [Public | Private] Pro
Property Let 语句 在 Class 块中,声明名称、参数和代码等,它们构成了赋值(设置)的 Property 过程的主体。 [Public | Private] Prop
我是一名优秀的程序员,十分优秀!