从1m15.605s到0m0.053s

事情源于昨天晚上butterfly的一个问题:找出一个文本文件中最长的一行,Find the longest line in a text file

由于我上大学后一些错误的观念,所以对算法极其的不重视。现在我所做的就是从头开始顺序读取,然后使用不同的编程语言看看效果。还是先看看結果吧:

环境:文件list.txt是一个16M的纯文本,测试的编程语言(当然有些不能说是编程语言)包括bash、ruby、gawk、python、wc、C(C写出来的效率竟然是wc命令的10多倍)

顺序:从最慢的bash到最快的C

1、BASH脚本

#FILE: long.sh, Author: ABitNo
#!/bin/bash
max=0
while read line; do
  if [ ${#line} -gt $max ]; then
    max=${#line}
    longest=$line
  fi
done
echo $max, $longest
exit 0

执行結果(結果会把最长的4082个字符给打印出来的,这里就不写了)

[mydream@archlinux c]$ time bash long.sh <list.txt
real	1m15.605s
user	1m8.349s
sys	0m6.910s

2、Ruby语言

#FILE: long.rb, Author: ABitNo
max, longest = 0, ''
IO.foreach(ARGV[0]) do |line|
  max, longest = line.length, line if line.length > max
end
puts max
puts longest

执行結果(結果会把最长的4082个字符给打印出来的,这里就不写了)

[mydream@archlinux c]$ time ruby long.rb list.txt
real	0m3.016s
user	0m2.517s
sys	0m0.463s

3、awk脚本

#FILE: long.awk, Author: ABitNo
{if ( length > max ) {
  max = length
  longest = $0
}}
END { 
  print max
  print longest 
}

执行結果(結果会把最长的4082个字符给打印出来的,这里就不写了)

[mydream@archlinux c]$ time gawk -f long.awk list.txt 
real	0m1.911s
user	0m1.863s
sys	0m0.017s

4、Python语言

#FILE: long.py, Author: ABitNo
maxLen = 0
for line in file(r'list.txt'):
  if maxLen < len(line):
    maxLen = len(line)
    longest = line
print maxLen
print longest

执行結果(結果会把最长的4082个字符给打印出来的,这里就不写了)

[mydream@archlinux c]$ time python long.py list.txt 
real	0m1.046s
user	0m1.027s
sys	0m0.020s

5、wc就是Linux上的一个小命令

执行結果(結果只会找出最长行的字数,而不会打印出那一行)

[mydream@archlinux c]$ time wc -L list.txt 
4082 list.txt
real	0m0.777s
user	0m0.757s
sys	0m0.003s

6、C语言,使用Linux API中文件到内存的存储映射mmap

/*FILE: long.c, Author: ABitNo*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, const char *argv[])
{
  int fd;
  struct stat sb;
  char *map;
  int loc = 0, max = 0, index = 0,  start = 0;

  if (argc < 2) {
    fprintf(stderr, "no input file\n");
    return 1;
  }

  /*打开文件*/
  fd = open(argv[1], O_RDONLY);
  if (fd == -1) {
    perror("open");
    return 1;
  }
  if (fstat(fd, &sb) == -1) {
    perror("fstat");
    return 1;
  }

  /*映射文件到内存*/
  map = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (map == MAP_FAILED) {
    perror("mmap");
    return 1;
  }

  /*关闭文件后映射依然可用*/
  if (close(fd) == -1) {
    perror("close");
    return 1;
  }
  
  /*循环遍历内存*/
  while (index < sb.st_size) {
    while('\n' != map[index++]);
    if (index - start > max) {
      loc = index - 1;
      max = loc - start;
    }
    start = index;
  }

  /*打印結果*/
  printf("max size: %d\n", max);
  for (index = loc-max; index < loc; index++) {
    putchar(map[index]);
  }
  putchar('\n');

  /*解除映射*/
  if (munmap(map, sb.st_size) == -1) {
    perror("munmap");
    return 1;
  }
  return 0;
}

执行結果(結果会把最长的4082个字符给打印出来的,这里就不写了)

[mydream@archlinux c]$ time ./long list.txt
real	0m0.053s
user	0m0.053s
sys	0m0.000s

那个执行一分多钟的脚本实在是无法忍受,从现在开始,我发现我相当的喜欢C语言了。

我还是得说,我是个数学天才,只是我一直在荒废自己的数学才华,因为我感觉不出在现在硬件发达的年代数学的作用。不过现在我开始了解到好的算法是很有必要的,即使硬件再发达,也会有一些小程序执行这么长时间,无法忍受的时间。。。

虽然说执行时间从1分15秒降低到了0.05秒,但这不是靠的算法的优化,因为我现在没有什么好的算法可用,现在开始,好好学习算法。。。

PS:我只是个一般的学生,写的代码都很差劲,期待有人指点。。。
再PS:如果有人能给算法的指点更好,但是不要告诉我詳細的程序,我得学习。。。

25 COMMENTS >>LEAVE<<

  1. andcat

    恩。 本人休息两周, 急性肠胃炎, 晕死。

  2. andcat

    ..上了几天的课程, 发现都不是我想要的, 算了, 自己整整吧。

  3. cbkid

    以前喜欢玩游戏,把数学荒废了。等待博主的算法帖子。

  4. ABitNo
    @andcat

    哈哈,我们现在一直都在休息,对面宿舍也被隔离了。。。

  5. ABitNo
    @andcat

    看了几分钟,没看出你是什么意思。。。

  6. ABitNo
    @cbkid

    我一直都不喜欢玩游戏。。。
    不过也有喜欢的,喜欢NFS,喜欢Tomb Raider。。。
    我的数学才能在等待复苏哈哈哈。。。

  7. happybabe
    @ABitNo

    NFS13:shift再次回归真实,可我找不到感觉
    从没学过算法,数学白痴路过

  8. kangzj

    用C语言是已经把整个文件读入到内存了吧,当然会很快很快的,16M内存根本算不了什么,但是如果一行一行读的话就完蛋了,浪费很多时间,也就是说,对其它语言来说有一些不公平,但是这也正是C的魅力所在,可以直接操作内存。
    有一个方法可以大大的提高速度——多线程并行计算,我写过相关的文章~

  9. ABitNo
    @kangzj

    哈哈,这个没有什么公平不公平的,我用ruby把东西都读到内存,用时4s。。。

    其实多线程在这里是没有什么速度优势的吧,CPU又不能实现真正的并行计算,不过现在的CPU大多是双核的,估计可以双线程。。。

    我现在就对算法有浓厚兴趣。。。看到很多优秀的blog,现在在看这个人的
    http://www.matrix67.com/blog
    一个中文系的学生对数学这么精通。。。

  10. kangzj
    @ABitNo

    我的意思就是多核多线程,这样才有意义,甚至可以用一个线程读数据(避免大数据内存放不下),几个线程来处理,
    算法跟数学还是两码事,不过确有相通之处
    推荐的博客不错,明天细看

  11. cbkid
    @happybabe

    NFS我的破集显压根就不想。
    而且NFS在wine下能跑?

  12. ABitNo
    @cbkid

    NFS在wine下可以的,先用wine把DirectX给安装好,然后再运行NFS,不过还是有时候会崩溃。。。

    不过古墓丽影似乎是OpenGL的?反正用Wine来运行相当流畅,什么问题都没有。。。

  13. sao30

    我的浏览器怎么错位

  14. ABitNo
    @sao30

    由于您使用的是非常低等的浏览器。。。
    系统提示:由于您的url包含色情信息,所以惨遭过虑

  15. Redhat

    哇,很多种方法啊 :)

  16. Redhat
    @ABitNo

    我第一次留言也不正常,现在好了

  17. soquick

    牛叉!!

  18. latteye

    文本处理的话 应该试试 perl。当然,和 C 还是无法比的。但是可能比 python 快。

  19. ABitNo
    @latteye

    这个我还是更关心有个高效的算法。。。

  20. iveney

    这个貌似跟算法与数学没多大关系.
    而是跟你的cache有关...
    另外你的C写的跟其它比起来是作弊阿...

    PS. 最好不要在matrix67 牛前说自己数学好...

  21. ABitNo
    @iveney

    这本来就没关系吗。。。我是在找算法。。。

    我也没有打算比较语言的优劣,只是看看我现在能写出多快的代码来。。。

    再者,要实事求是,我数学就是好,没的说。。。

    哈哈。。。

  22. Lc.

    强人~~ 懂这么多种语言~
    wc跟awk我还是比较常用的

  23. wayne

    感觉现在大学里很少有人强调算法的重要性了,尤其是本科教育

  24. wn

    随便看了一眼你的ruby和python,你的写法让程序慢了一倍。
    len(string)
    string.length用两次就是执行两次。
    而这个算法里最慢的就是这个操作。

    你把最慢的操作做了每一行都做了2遍。。。。

  25. ABitNo
    @wn

    这样啊,以后注意了,谢谢

LEAVE A RESPONSE >>CANCEL<<

loader