簡體   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