2009-05-30 15 views
79

Il comando UNIX sort possibile ordinare un file molto grande in questo modo:In che modo il comando di ordinamento UNIX può ordinare un file molto grande?

sort large_file 

Come è l'algoritmo di ordinamento attuata?

Come mai non causa un consumo eccessivo di memoria?

+0

Modificato di nuovo il comando. UUoC. ;) – ayaz

+0

Questo è interessante. Non so davvero come funziona, ma ho una supposizione. Probabilmente mette il primo carattere di ogni chiave in un albero binario, e quando c'è una collisione, usa anche il prossimo carattere della chiave, quindi non salva più la chiave del necessario.Può quindi salvare un offset nel file con ciascun tasto in modo che possa cercare e stampare ogni riga in ordine. – Zifre

+0

In realtà, @ayaz è più interessante se non si ordina un file su disco ma piuttosto in una pipe poiché è ovvio che non è possibile eseguire più passaggi sui dati di input. – tvanfosson

risposta

93

Algorithmic details of UNIX Sort command dice che Unix Sort utilizza un algoritmo di ordinamento di fusione merker 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 ciascuna porzione alla fine.

33

Il comando sort memorizza i dati di lavoro nei file del disco temporanei (in genere in /tmp).

+16

usa '-T' per specificare la directory temporanea –

11

Non ho dimestichezza con il programma, ma suppongo che sia fatto per mezzo di un ordinamento esterno (la maggior parte del problema è contenuta in file temporanei mentre una parte relativamente piccola del problema è conservata in memoria alla volta). Vedi Donald Knuth's The Art of Computer Programming, Vol. 3 Sorting and Searching, Section 5.4 per una discussione molto approfondita sull'argomento.

13

ATTENZIONE: Questo script avvia una shell per blocco, per file molto grandi, potrebbe essere centinaia.


Ecco uno script 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 

Consulta anche: "Sorting large files faster with a shell script"

+27

Puoi semplicemente usare sort --parallel N a partire dalla versione di ordinamento GNU 8.11 – jhclark

+4

GNU coreutils 8.6 in realtà – bdeonovic

+1

Questo ha fatto il trucco per me. Ho una versione 8.4. Usare ordinamento direttamente sul file (190 milioni di righe) non andava dove. Questo programma lo ha fatto con poco meno di 4 minuti –

-4

memoria non dovrebbe essere un problema - sorta già si occupa di questo. Se vuoi fare un uso ottimale della tua CPU multi-core, lo ho implementato in un piccolo script (simile ad alcuni che potresti trovare in rete, ma più semplice/più 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* 
+4

Script interessante, ma non fa nulla per rispondere a questa domanda. –

+5

split -b dividerà per byte, troncando le linee in una posizione arbitraria – ithkuil

11
#!/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 
+0

Questo è eccellente. Non ero a conoscenza del fatto che esisteva un pacchetto parallelo! Il tempo di ordinamento è migliorato di oltre il 50% dopo aver utilizzato quanto sopra. Grazie. – xbsd

+0

Ho provato a usare comm a diff sui file generati da questo e mi sta avvisando che i file non sono ordinati. – ashishb

4

Guardate attentamente le opzioni di sorta per velocizzare le prestazioni e capire il suo impatto sulla vostra macchina e di problem. parametri chiave su Ubuntu sono

  • posizione dei file temporanei -t directory_name
  • quantità di memoria da utilizzare -SN% (N% di tutta la memoria da utilizzare, più sono e meglio, ma evitare un eccesso di sottoscrizione che provoca è possibile utilizzarlo come "-S 80%" per utilizzare l'80% della RAM disponibile o "-S 2G" per 2 GB di RAM.)

L'interrogante chiede "Perché non utilizza memoria elevata ?" La risposta a questo viene dalla cronologia, le macchine unix precedenti erano piccole e la dimensione della memoria predefinita è ridotta. Regola il più grande possibile per il tuo carico di lavoro per migliorare notevolmente le prestazioni di ordinamento. Imposta la directory di lavoro in un punto del tuo dispositivo più veloce che abbia spazio sufficiente per contenere almeno 1,25 * la dimensione del file che viene ordinato.

+0

provandolo su un file da 2,5 GB, su una scatola con 64 GB di RAM con -S 80%, in realtà utilizza quella percentuale completa, anche se l'intero file è più piccolo di quello. perché? anche se non utilizza un ordinamento sul posto che sembra gratuito –

+0

Probabilmente sort -S pre-alloca la memoria per il processo di ordinamento prima ancora di leggere il contenuto del file. –

Problemi correlati