繁体   English   中英

为什么用C编写的行计数函数比Ruby慢?

[英]Why is my line count function written in C slower than Ruby?

我有一个函数的两种实现,可打印给定文件中的行数,一种用C编写,另一种用Ruby编写。 出于某些奇怪的原因,Ruby版本快2倍! 这是代码:

linecount.c (与gcc linecount.c -o linecount编译)

#include <stdio.h>

int main(int argc, char **argv) {
  FILE *fp;
  int c;
  int count;

  fp = fopen(argv[1], "r");

  while ((c = getc(fp)) != EOF) {
    if (c == '\n') {
      count++;
    }
  }

  fclose(fp);
  printf("%d\n", count);
  return 0;
}

ruby_linecount.rb

#!/usr/bin/env ruby

puts File.open(ARGV[0]).lines.count

这些是基准:

time (for i in {1..100}; do ./linecount /usr/share/dict/words; done)
real    0m14.438s 
user    0m14.041s
sys     0m0.298s

time (for i in {1..100}; do ./ruby_linecount.rb /usr/share/dict/words; done)
real    0m6.910s
user    0m5.917s
sys     0m0.734s

为什么C版本这么慢? 如何提高C代码的性能? 是否有任何有助于编译的标志?

您可以使用编译器选项-O3来优化性能。 您也可以考虑使用fgets来避免逐字符读取文件。

从文件读取是高延迟操作。 最有可能的是,通过从文件中读取较大的数据块,可以提高C版本的速度。

我提供两个例子。

第一个使用16K缓冲区。 可以更改缓冲区大小以查看更好的性能。

例1

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define BUFSIZE (16 * 1024)

int main(int argc, char **argv)
   {
   int rCode;
   FILE *fp = NULL;
   char *buf = NULL;
   int count = 0;
   size_t bufLen;

   errno=0;
   fp = fopen(argv[1], "r");
   if(NULL == fp)
      {
      rCode=errno;
      fprintf(stder, "fopen() failed.  errno:%d\n", errno);
      goto CLEANUP;
      }

   errno=0;
   buf = malloc(BUFSIZE);
   if(NULL == buf)
      {
      rCode=errno;
      fprintf(stder, "malloc() failed.  errno:%d\n", errno);
      goto CLEANUP;
      }

   bufLen = fread(buf, 1, BUFSIZE, fp);
   while(bufLen)
      {
      char *cp;

      for(cp=buf; (cp < buf + bufLen); ++cp)
         if('\n' == *cp)
            ++count;

          bufLen = fread(buf, 1, BUFSIZE, fp);
      }

   printf("%d\n", count);

CLEANUP:

   if(fp)
      fclose(fp);

   if(buf)
      free(buf);

   return(rCode);
   }

下一个将文件映射到进程内存映射(或地址空间)中。 然后,寻找search for newlines就是search for newlines进行内存search for newlines

例子2

#include <errno.h>    /* errno, ... */
#include <fcntl.h>    /* open(), O__RDONLY, ... */
#include <stdio.h>    /* fprintf(), stderr, printf(), ... */
#include <sys/mman.h> /* mmap(), PROT_READ, MAP_SHARED, ... */
#include <sys/stat.h> /* fstat(), struct stat, ... */
#include <unistd.h>   /* close(), ... */

int main(int argc, char **argv)
   {
   int rCode=0;
   int fd = (-1);
   struct stat statBuf;
   char *fileBuf=NULL;
   char *cp;
   int   count=0;

   errno=0;
   fd = open(argv[1], O_RDONLY);
   if((-1) == fd)
      {
      rCode=errno;
      fprintf(stderr, "open() failed.  errno:%d\n", errno);
      goto CLEANUP;
      }

   errno=0;
   if((-1) == fstat(fd, &statBuf))
      {
      rCode=errno;
      fprintf(stderr, "fstat() failed.  errno:%d\n", errno);
      goto CLEANUP;
      }

   errno=0;
   fileBuf = mmap(
         NULL,            /* preferred start address, normally NULL (system chooses) */
         statBuf.st_size, /* length of the mapped region */
         PROT_READ,       /* memory protection */
         MAP_SHARED,      /* private/shared */
         fd,              /* fd of mapped file */
         0                /* file offset (should be a multiples of a page) */
         );
   if((void *)(-1) == fileBuf)
      {
      rCode=errno;
      fprintf(stderr, "mmap() failed.  errno:%d\n", errno);
      goto CLEANUP;
      }

   for(cp=fileBuf; cp < fileBuf + statBuf.st_size; ++cp)
      if('\n' == *cp)
         ++count;

  printf("%d\n", count);

CLEANUP:

   if(fileBuf)
      munmap(fileBuf, statBuf.st_size);

   if((-1) != fd)
      close(fd);

   return(rCode);
   }

编辑

我同意Neil Slater's评论。 尽管上面的示例可以提高操作速度(与问题代码中的示例相比); 也许Ruby会很快。

在MacBook Pro上使用代码会显示C版本的错误结果。 我建议将while循环更改为此:

 while ( (c=fgetc(fp)) != EOF )

使用fgetc而不是getc 而且,您可以按照前面建议的-O3标志来优化编译器。

对于ruby代码,最好使用each_line而不是lines (这是已弃用的别名)。

根据所使用的红宝石版本,可以获得不同的结果。 在我的机器上,ruby比相应的C代码慢大约50倍。

您正在尝试做的事情应该是严重的IO约束。 换句话说,大部分时间都花在读取文件而不是进行实际计算上。 您应该尝试使用另一种方式来读取C版本中的文件,并且也许看看Ruby正在使用什么。

我猜想mmap可以给您比getc更好的性能。

另外,请注意基准测试程序的顺序。 在其中一个程序第一次运行后,该文件可能会在内存缓存中,从而使另一个程序更快。 您应该多次运行每个程序,以获得更准确的时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM