Come può il comando UNIX sort ordinare un file molto grande?


104

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?


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

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

3
Perché tutti su SO si sentono così spinti a indovinare tutto il tempo?

Puoi eseguire più passaggi sull'input: devi solo leggere tutto l'input, scriverlo su disco e quindi ordinare il file su disco.

2
@ Neil - dal contesto sembrava ovvio che stesse cercando di ordinare il contenuto del file e non il nome del file (che per un nome è privo di significato). Volevo solo migliorare la domanda senza cambiare troppo il contesto in modo da ottenere risposte invece di voti negativi a causa di un semplice errore.
tvanfosson

Risposte:


111

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.


42

Il sortcomando memorizza i dati di lavoro in file temporanei del disco (di solito in /tmp).


20
utilizzare -Tper specificare la
directory

12

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 "


35
Puoi semplicemente usare sort --parallel N a partire da GNU sort versione 8.11
jhclark

5
GNU coreutils 8.6 in realtà
bdeonovic

1
Questo ha fatto il trucco per me. Ho la versione 8.4 di ordinamento. Usare l'ordinamento direttamente sul file (190 milioni di righe) non stava andando da nessuna parte. Questo programma lo ha fatto con poco meno di 4 minuti
Sunil B

ancora una volta, questa risposta non ha nulla a che fare con la domanda
WattsInABox

2
Questo script è pericoloso. La mia macchina Linux ha perso la risposta dopo aver lanciato centinaia di processi di ordinamento ...
Yongwei Wu


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

Questo è eccellente. Non sapevo che ci fosse un pacchetto parallelo! Il tempo di ordinamento è migliorato di oltre il 50% dopo aver utilizzato quanto sopra. Grazie.
xbsd

Ho provato a usare la comunicazione per diff sui file generati da questo e mi dava un avviso che i file non sono ordinati.
ashishb

7

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

  • Posizione dei file temporanei -T nome_directory
  • Quantità di memoria da usare -SN% (N% di tutta la memoria da usare, più è meglio è, ma evita l'abbonamento eccessivo che causa lo scambio su disco. Puoi usarlo come "-S 80%" per utilizzare l'80% della RAM disponibile, o "-S 2G" per 2 GB di RAM.)

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.


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

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

-3

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*

4
Sceneggiatura interessante, ma non fa nulla per rispondere a questa domanda.
Joachim Sauer

5
split -b verrà diviso per byte, troncando così le linee in una posizione arbitraria
ithkuil
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.