Der UNIX- sort
Befehl kann eine sehr große Datei wie folgt sortieren:
sort large_file
Wie ist der Sortieralgorithmus implementiert?
Wie kommt es, dass es keinen übermäßigen Speicherverbrauch verursacht?
Der UNIX- sort
Befehl kann eine sehr große Datei wie folgt sortieren:
sort large_file
Wie ist der Sortieralgorithmus implementiert?
Wie kommt es, dass es keinen übermäßigen Speicherverbrauch verursacht?
Antworten:
Die algorithmischen Details des UNIX -Sortierbefehls besagen, dass Unix Sort einen externen R-Way-Merge-Sortieralgorithmus verwendet. Der Link geht auf weitere Details ein, teilt die Eingabe jedoch im Wesentlichen in kleinere Teile (die in den Speicher passen) auf und führt dann jeden Teil am Ende zusammen.
Der sort
Befehl speichert Arbeitsdaten in temporären Datenträgerdateien (normalerweise in /tmp
).
-T
, um die Temperatur dir
WARNUNG: Dieses Skript startet eine Shell pro Block. Bei sehr großen Dateien können dies Hunderte sein.
Hier ist ein Skript, das ich zu diesem Zweck geschrieben habe. Auf einem 4-Prozessor-Computer wurde die Sortierleistung um 100% verbessert!
#! /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
Siehe auch: " Große Dateien mit einem Shell-Skript schneller sortieren "
Ich bin mit dem Programm nicht vertraut, aber ich denke, es wird durch externe Sortierung durchgeführt (der größte Teil des Problems wird in temporären Dateien gespeichert, während ein relativ kleiner Teil des Problems gleichzeitig im Speicher gespeichert wird). Siehe Donald Knuths The Art of Computer Programming, Vol. 3, No. 3 Sortieren und Suchen, Abschnitt 5.4 für eine sehr eingehende Diskussion des Themas.
#!/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
Schauen Sie sich die Sortieroptionen genau an, um die Leistung zu beschleunigen, und verstehen Sie die Auswirkungen auf Ihre Maschine und Ihr Problem. Wichtige Parameter unter Ubuntu sind
Der Fragesteller fragt: "Warum keine hohe Speichernutzung?" Die Antwort darauf stammt aus der Geschichte, ältere Unix-Maschinen waren klein und die Standardspeichergröße ist klein eingestellt. Passen Sie dies so groß wie möglich an, damit Ihre Arbeitslast die Sortierleistung erheblich verbessert. Stellen Sie das Arbeitsverzeichnis auf einen Ort auf Ihrem schnellsten Gerät ein, der über genügend Speicherplatz für mindestens 1,25 * der Größe der zu sortierenden Datei verfügt.
Der Speicher sollte kein Problem sein - die Sortierung kümmert sich bereits darum. Wenn Sie Ihre Multi-Core-CPU optimal nutzen möchten, habe ich dies in einem kleinen Skript implementiert (ähnlich wie einige, die Sie im Internet finden, aber einfacher / sauberer als die meisten anderen;)).
#!/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*