Comment la commande de sorting UNIX peut-elle sortinger un fichier très volumineux?

La commande de sort UNIX peut sortinger un fichier très volumineux comme ceci:

 sort large_file 

Comment l’algorithme de sorting est-il implémenté?

Comment se fait-il que cela ne provoque pas une consommation excessive de mémoire?

La commande Algorithmic details of UNIX Sort indique que Unix Sort utilise un algorithme de sorting de fusion R-Way externe. Le lien entre plus de détails, mais il divise essentiellement l’entrée en parties plus petites (qui correspondent à la mémoire), puis fusionne chaque partie à la fin.

La commande de sort stocke les données de travail dans des fichiers de disques temporaires (généralement dans /tmp ).

ATTENTION: Ce script lance un shell par bloc, pour des fichiers vraiment volumineux, cela peut être des centaines.


Voici un script que j’ai écrit à cet effet. Sur une machine à 4 processeurs, les performances de sorting ont été améliorées de 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 

Voir aussi: ” Tri plus rapide des fichiers volumineux avec un script shell ”

Je ne suis pas familier avec le programme, mais je suppose que cela se fait au moyen d’un sorting externe (la plupart du problème est contenu dans des fichiers temporaires alors qu’une partie relativement petite du problème est conservée en mémoire à la fois). Voir L’art de la programmation informatique de Donald Knuth , vol. 3 Tri et recherche, section 5.4 pour une discussion très approfondie du sujet.

 #!/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 

Examinez attentivement les options de sorting pour accélérer les performances et comprendre son impact sur votre machine et votre problème. Les parameters clés sur Ubuntu sont

  • Emplacement des fichiers temporaires -T nom_répertoire
  • Quantité de mémoire à utiliser -SN% (N% de la mémoire à utiliser, mieux c’est, mais évitez les surabonnements qui provoquent un échange sur disque. Vous pouvez l’utiliser comme “-S 80%” pour utiliser 80% de la RAM disponible, ou “-S 2G” pour 2 Go de RAM.)

Le questionneur demande “Pourquoi pas de mémoire élevée?” La réponse à cette question vient de l’histoire, les anciennes machines Unix étaient petites et la taille de la mémoire par défaut était petite. Ajustez-le le plus possible pour que votre charge de travail améliore considérablement les performances de sorting. Définissez le répertoire de travail sur un emplacement sur votre périphérique le plus rapide qui dispose de suffisamment d’espace pour contenir au moins 1,25 * la taille du fichier en cours de sorting.

La mémoire ne devrait pas être un problème – le sorting en prend déjà soin. Si vous voulez utiliser au mieux votre processeur multi-core, je l’ai implémenté dans un petit script (similaire à certains que vous trouverez sur le net, mais plus simple / plus propre que la plupart d’entre eux)).

 #!/bin/bash # Usage: psort filename   # 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 hp 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*