【问题标题】:How could the UNIX sort command sort a very large file?UNIX 排序命令如何对一个非常大的文件进行排序?
【发布时间】:2010-10-30 03:00:32
【问题描述】:

UNIX sort 命令可以像这样对非常大的文件进行排序:

sort large_file

排序算法是如何实现的?

怎么不会造成内存过度消耗?

【问题讨论】:

  • 这很有趣。我真的不知道它是如何工作的,但我有一个猜测。它可能会将每个键的第一个字符放入二叉树中,当发生冲突时,它也会使用键的下一个字符,因此它不会保存比需要更多的键。然后它可以使用每个键将偏移量保存到文件中,以便它可以按顺序查找并打印每一行。
  • 实际上,@ayaz 如果您不是在磁盘上而是在管道中对文件进行排序,它会更有趣,因为很明显您不能简单地对输入数据进行多次传递。
  • 为什么 SO 上的每个人都觉得总要猜测?
  • 您可以对输入进行多次传递 - 您只需读取所有输入,将其写入磁盘,然后对磁盘文件进行排序。
  • @Neil - 从上下文来看,很明显他试图对文件的内容而不是文件名进行排序(对于一个名称来说,这是没有意义的)。我只是想在不过多改变上下文的情况下改进问题,以便它得到答案而不是因为一个简单的错误而被否决。

标签: shell sorting


【解决方案1】:

Algorithmic details of UNIX Sort command 表示 Unix 排序使用外部 R-Way 合并排序算法。该链接包含更多细节,但实质上它将输入分成更小的部分(适合内存),然后在最后将每个部分合并在一起。

【讨论】:

    【解决方案2】:

    sort 命令将工作数据存储在临时磁盘文件中(通常在/tmp 中)。

    【讨论】:

    • 使用-T指定临时目录
    【解决方案3】:

    我不熟悉该程序,但我猜它是通过外部排序完成的(大部分问题保存在临时文件中,而相对较小的部分问题一次保存在内存中)。请参阅 Donald Knuth 的 The Art of Computer Programming, Vol. 3 Sorting and Searching, Section 5.4,了解对该主题的深入讨论。

    【讨论】:

      【解决方案4】:

      警告:此脚本为每个块启动一个 shell,对于非常大的文件,这可能是数百个。


      这是我为此目的编写的一个脚本。在 4 处理器机器上,它提高了 100% 的排序性能!

      #! /bin/ksh
      
      MAX_LINES_PER_CHUNK=1000000
      ORIGINAL_FILE=$1
      SORTED_FILE=$2
      CHUNK_FILE_PREFIX=$ORIGINAL_FILE.split.
      SORTED_CHUNK_FILES=$CHUNK_FILE_PREFIX*.sorted
      
      usage ()
      {
           echo Parallel sort
           echo usage: psort file1 file2
           echo Sorts text file file1 and stores the output in file2
           echo Note: file1 will be split in chunks up to $MAX_LINES_PER_CHUNK lines
           echo  and each chunk will be sorted in parallel
      }
      
      # test if we have two arguments on the command line
      if [ $# != 2 ]
      then
          usage
          exit
      fi
      
      #Cleanup any lefover files
      rm -f $SORTED_CHUNK_FILES > /dev/null
      rm -f $CHUNK_FILE_PREFIX* > /dev/null
      rm -f $SORTED_FILE
      
      #Splitting $ORIGINAL_FILE into chunks ...
      split -l $MAX_LINES_PER_CHUNK $ORIGINAL_FILE $CHUNK_FILE_PREFIX
      
      for file in $CHUNK_FILE_PREFIX*
      do
          sort $file > $file.sorted &
      done
      wait
      
      #Merging chunks to $SORTED_FILE ...
      sort -m $SORTED_CHUNK_FILES > $SORTED_FILE
      
      #Cleanup any lefover files
      rm -f $SORTED_CHUNK_FILES > /dev/null
      rm -f $CHUNK_FILE_PREFIX* > /dev/null
      

      另请参阅: "Sorting large files faster with a shell script"

      【讨论】:

      • 从 GNU 排序版本 8.11 开始,您可以只使用 sort --parallel N
      • GNU coreutils 8.6 实际上
      • 这个对我有用。我有排序 8.4 版本。直接在文件(1.9 亿行)上使用排序是无济于事的。这个程序不到 4 分钟就完成了
      • 这个脚本很危险。我的 Linux 机器在启动数百个排序进程后失去响应……
      • @WattsInABox 这叫做微妙的弯曲。
      【解决方案5】:

      内存应该不是问题 - sort 已经解决了这个问题。如果您想充分利用您的多核 CPU,我已经在一个小脚本中实现了这一点(类似于您可能在网上找到的一些脚本,但比大多数脚本更简单/更干净;))。

      #!/bin/bash
      # Usage: psort filename <chunksize> <threads>
      # In this example a the file largefile is split into chunks of 20 MB.
      # The part are sorted in 4 simultaneous threads before getting merged.
      # 
      # psort largefile.txt 20m 4    
      #
      # by h.p.
      split -b $2 $1 $1.part
      suffix=sorttemp.`date +%s`
      nthreads=$3
      i=0
      for fname in `ls *$1.part*`
      do
          let i++
          sort $fname > $fname.$suffix &
          mres=$(($i % $nthreads))
          test "$mres" -eq 0 && wait
      done
      wait
      sort -m *.$suffix 
      rm $1.part*
      

      【讨论】:

      • 有趣的脚本,但它无法回答这个问题。
      • split -b 将按字节拆分,从而截断任意位置的行
      【解决方案6】:
      #!/bin/bash
      
      usage ()
      {
          echo Parallel sort
          echo usage: psort file1 file2
          echo Sorts text file file1 and stores the output in file2
      }
      
      # test if we have two arguments on the command line
      if [ $# != 2 ]
      then
          usage
          exit
      fi
      
      pv $1 | parallel --pipe --files sort -S512M | parallel -Xj1 sort -S1024M -m {} ';' rm {} > $2
      

      【讨论】:

      • 这太棒了。不知道有一个并行包!使用上述方法后,排序时间提高了 50% 以上。谢谢。
      • 我尝试使用 comm 对由此生成的文件进行比较,并警告我文件未排序。
      【解决方案7】:

      仔细查看排序选项以提高性能并了解它对您的机器和问题的影响。 Ubuntu 上的关键参数是

      • 临时文件的位置 -T directory_name
      • 要使用的内存量 -S N% (N% of all memory to use,越多越好但是 避免过度订阅导致交换到磁盘。您可以像“-S 80%”一样使用它来使用 80% 的可用 RAM,或者像“-S 2G”一样使用 2 GB RAM。)

      提问者问“为什么没有高内存使用?”答案来自历史,旧的 unix 机器很小,默认的内存大小设置得很小。为您的工作负载尽可能大地调整它,以极大地提高排序性能。将工作目录设置在您最快的设备上的一个位置,该位置有足够的空间容纳至少 1.25 * 被排序文件的大小。

      【讨论】:

      • 在 2.5GB 文件、64GB RAM 和 -S 80% 的机器上尝试此操作,它实际上正在使用该完整百分比,即使整个文件小于该值。这是为什么?即使它不使用看起来无缘无故的就地排序
      • 可能 sort -S 在读取文件内容之前为排序过程预先分配内存。
      【解决方案8】:

      如何使用 -T 选项对大文件进行排序

      我必须对一个大文件的第 7 列进行排序。

      我正在使用:

      grep vdd  "file name" | sort -nk 7 |
      

      我遇到以下错误:

      ******sort: write failed: /tmp/sort1hc37c: No space left on device******
      

      然后我使用了 -T 选项,如下所示:

      grep vdda  "file name" | sort -nk 7  -T /dev/null/ |
      

      【讨论】:

      • 请使用除 /dev/null 之外的其他示例目录。
      猜你喜欢
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 2018-07-22
      • 2011-08-01
      相关资源
      最近更新 更多