Il sortcomando UNIX può ordinare un file molto grande come questo:
sort large_file
Come viene implementato l'algoritmo di ordinamento?
Come mai non provoca un consumo eccessivo di memoria?
Il sortcomando UNIX può ordinare un file molto grande come questo:
sort large_file
Come viene implementato l'algoritmo di ordinamento?
Come mai non provoca un consumo eccessivo di memoria?
Risposte:
I dettagli algoritmici del comando UNIX Sort dicono che Unix Sort utilizza un algoritmo di ordinamento di unione R-Way esterno. Il collegamento entra in maggiori dettagli, ma in sostanza divide l'input in porzioni più piccole (che si adattano alla memoria) e quindi unisce ogni porzione insieme alla fine.
ATTENZIONE: questo script avvia una shell per blocco, per file molto grandi, potrebbero essere centinaia.
Ecco una sceneggiatura che ho scritto per questo scopo. Su una macchina a 4 processori ha migliorato le prestazioni di ordinamento del 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
Vedi anche: " Ordinare file di grandi dimensioni più velocemente con uno script di shell "
Non ho familiarità con il programma, ma immagino che sia fatto tramite l'ordinamento esterno (la maggior parte del problema è contenuta in file temporanei mentre una parte relativamente piccola del problema viene mantenuta in memoria alla volta). Vedi The Art of Computer Programming di Donald Knuth , Vol. 3 Ordinamento e ricerca, Sezione 5.4 per una discussione molto approfondita sull'argomento.
#!/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
Esamina attentamente le opzioni di ordinamento per accelerare le prestazioni e comprendi il suo impatto sulla tua macchina e sul problema. I parametri chiave su Ubuntu sono
L'interrogante chiede "Perché nessun utilizzo elevato della memoria?" La risposta a questa domanda viene dalla storia, le macchine Unix più vecchie erano piccole e la dimensione della memoria predefinita è piccola. Regola questo il più grande possibile per il tuo carico di lavoro per migliorare notevolmente le prestazioni di ordinamento. Imposta la directory di lavoro in una posizione sul tuo dispositivo più veloce che abbia spazio sufficiente per contenere almeno 1,25 * la dimensione del file da ordinare.
La memoria non dovrebbe essere un problema: sort si occupa già di questo. Se vuoi fare un uso ottimale della tua CPU multi-core, l'ho implementato in un piccolo script (simile ad alcuni che potresti trovare in rete, ma più semplice / pulito della maggior parte di quelli;)).
#!/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*