我听说 scanf() “花费很多”,但现在我找不到任何相关信息。
是的,这是真的。在许多情况下它会比较慢。
特别是逐字节读取文件:
int chr;
// this is much slower than ...
while (1) {
if (fscanf(xf,"%c",&chr) != 1)
break;
}
// ... this
while (1) {
chr = fgetc(xf);
if (chr == EOF)
break;
}
旁注:信不信由你,以上来自我遇到的一个真实世界的生产级程序[用于将固件加载到 FPGA 中]。我使用fgetc [和read] 修复了它。我将运行时间从 15 分钟减少到 90 秒
附加问题:您能否推荐一些资源来获取此类信息,了解某个功能对程序的成本是多少?
您可以了解“大 O”符号和分析。
但是,您始终可以编写基准程序。这是我创建的一个,可以帮助您创建自己的。
在这种特殊情况下,重要的是从时序中消除 I/O 的开销。因此,该程序在 缓冲区 中创建随机行,并在缓冲区上执行 strtod 或 sscanf。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TSTMAX 100000
#define FNCMAX 2
typedef long long tsc_t;
tsc_t
tscget(void)
{
struct timespec ts;
tsc_t tsc;
clock_gettime(CLOCK_MONOTONIC,&ts);
tsc = ts.tv_sec;
tsc *= 1000000000;
tsc += ts.tv_nsec;
return tsc;
}
double
tscsec(tsc_t tsc)
{
double sec;
sec = tsc;
sec /= 1e9;
return sec;
}
tsc_t elap[FNCMAX][TSTMAX];
void
useit(double *arr)
{
}
void
doscanf1(char *buf)
{
double arr[4];
sscanf(buf,"%lf %lf %lf %lf",&arr[0],&arr[1],&arr[2],&arr[3]);
useit(arr);
}
void
doscanf2(char *buf)
{
double arr[4];
sscanf(buf,"%lf %lf %lf %lf",&arr[0],&arr[1],&arr[2],&arr[3]);
useit(arr);
}
void
dotok(char *buf)
{
double arr[4];
for (int idx = 0; idx < 4; ++idx)
arr[idx] = strtod(buf,&buf);
useit(arr);
}
void
dofnc(int tstidx,int fncidx,const char *src)
{
char buf[1000];
tsc_t tscbeg;
tsc_t tscend;
strcpy(buf,src);
tscbeg = tscget();
switch (fncidx) {
case 0:
dotok(buf);
break;
case 1:
doscanf1(buf);
break;
case 2:
doscanf2(buf);
break;
}
tscend = tscget();
tscend -= tscbeg;
elap[fncidx][tstidx] = tscend;
}
void
dotest(int tstidx)
{
char *bp;
char buf[1000];
bp = buf;
for (int idx = 0; idx < 4; ++idx)
bp += sprintf(bp," %.8g",drand48());
dofnc(tstidx,0,buf);
dofnc(tstidx,1,buf);
}
int
cmpfnc(const void *lhs,const void *rhs)
{
tsc_t dif = *(const tsc_t *) lhs - *(const tsc_t *) rhs;
int cmpflg;
do {
cmpflg = -1;
if (dif < 0)
break;
cmpflg = 1;
if (dif > 0)
break;
cmpflg = 0;
} while (0);
return cmpflg;
}
int
main(void)
{
tsc_t avg[FNCMAX] = { 0 };
for (int tstidx = 0; tstidx < TSTMAX; ++tstidx)
dotest(tstidx);
for (int fncidx = 0; fncidx < FNCMAX; ++fncidx)
qsort(&elap[fncidx][0],TSTMAX,sizeof(tsc_t),cmpfnc);
for (int tstidx = 0; tstidx < TSTMAX; ++tstidx) {
for (int fncidx = 0; fncidx < FNCMAX; ++fncidx) {
tsc_t tsc = elap[fncidx][tstidx];
printf(" %.9f",tscsec(tsc));
avg[fncidx] += tsc;
}
printf(" %d\n",tstidx);
}
for (int fncidx = 0; fncidx < FNCMAX; ++fncidx) {
tsc_t tsc = avg[fncidx];
printf("TOT:%.9f AVG:%.9f\n",tscsec(tsc),tscsec(tsc) / TSTMAX);
}
}
您可以运行上述程序。以下是在我的系统上运行的摘要:
TOT:0.090690979 AVG:0.000000907
TOT:0.157146016 AVG:0.000001571
因此,使用 strtod 几乎比 sscanf 快 1.75 倍