目前我想比较Python和C在处理字符串时的速度。我认为C应该比Python提供更好的性能;但是,我得到了完全相反的结果。在
以下是C程序:
#include <unistd.h>
#include <sys/time.h>
#define L (100*1024)
char s[L+1024];
char c[2*L+1024];
double time_diff( struct timeval et, struct timeval st )
{
return 1e-6*((et.tv_sec - st.tv_sec)*1000000 + (et.tv_usec - st.tv_usec ));
}
int foo()
{
strcpy(c,s);
strcat(c+L,s);
return 0;
}
int main()
{
struct timeval st;
struct timeval et;
int i;
//printf("s:%x\nc:%x\n", s,c);
//printf("s=%d c=%d\n", strlen(s), strlen(c));
memset(s, '1', L);
//printf("s=%d c=%d\n", strlen(s), strlen(c));
foo();
//printf("s=%d c=%d\n", strlen(s), strlen(c));
//s[1024*100-1]=0;
gettimeofday(&st,NULL);
for( i = 0 ; i < 1000; i++ ) foo();
gettimeofday(&et,NULL);
printf("%f\n", time_diff(et,st));
return 0;
}
这是Python的一个:
^{pr2}$我得到的是:
root@xkqeacwf:~/lab/wfaster# python cp100k.py
0.027932882309
root@xkqeacwf:~/lab/wfaster# gcc cp100k.c
root@xkqeacwf:~/lab/wfaster# ./a.out
0.061820
有道理吗?还是我犯了什么愚蠢的错误?在
我认为这是因为Python字符串不是以null结尾的。在
在Python中,字符串长度存储在字符串旁边,允许它在连接字符串时跳过strcat()使用的隐式strlen()。在
原因可能是字符串连接是直接用C实现的。在
编辑:好吧,现在我实际查看了C代码,发现它使用静态缓冲区,我也很困惑,因为我不明白Python如何避免动态分配,而动态分配应该慢得多。。。在
累积的意见(主要是我的意见)转化为答案:
memmove()
或{strcpy()
和{strcat()
可以被strcpy()
替换,结果没有差别——检查时间可能很有趣。)另外,您没有包括<string.h>
(或<stdio.h>
),因此您错过了<string.h>
可能提供的任何优化!在更简单的测试,而不是(count或是null byte')“这是空字节吗”。在memmove()
的代码是高度优化的汇编程序,可能是内联的(没有函数调用开销,但是对于100KiB的数据,函数调用开销最小)。好处是从更大的移动和更简单的循环条件。在memmove()
或{memcpy()
也可以正常工作;memcpy()
如果它们重叠,就没有义务正确工作)。相对而言,他们不太可能有比memmove/memcpy
更快的东西。在我修改了C代码以在我的机器上生成更稳定的计时(macosx10.7.4,8gib1333mhz RAM,2.3ghz英特尔酷睿i7,gcc4.7.1),并比较了}vs
strcpy()
和{memcpy()
vsmemmove()
。请注意,我将循环计数从1000增加到10000,以提高计时的稳定性,并且我将整个测试(所有三种机制)重复10次。可以说,定时循环计数应该再增加5-10倍,以便计时超过一秒钟。在编译时不会发出警告:
^{pr2}$我得到的时机是:
奇怪的是,如果我忽略了“no warnings”而忽略了}头,就像在最初发布的代码中一样,我得到的计时是:
<string.h>
和{仔细观察这些结果,它似乎比“更干净”的代码要快,尽管我没有对这两组数据进行学生t检验,而且计时具有非常大的可变性(但我确实有类似Boinc在后台运行8个进程的东西)。在代码的早期版本中,效果似乎更为明显,当时只测试了}。如果这是真的效果,我无法解释!在
strcpy()
和{由mvds跟进
既然问题已经结束了,我就不能正确回答了。在Mac电脑上,几乎什么都不做,我得到了以下时间安排:
(带标题)
(无标题,忽略警告)
预处理器输出(
-E
标志)显示,包含头会将strcpy
转换为如下内置调用:因此strcpy的libc版本的性能优于gcc内置版本。(使用
gdb
可以很容易地验证strcpy
上的断点在strcpy()
调用中确实没有中断,如果包含头的话)在Linux(Debian5.0.9,amd64)上,这些差异似乎可以忽略不计。生成的程序集(
-S
标志)只在include携带的调试信息上有所不同。在相关问题 更多 >
编程相关推荐