O sort
comando UNIX pode classificar um arquivo muito grande como este:
sort large_file
Como o algoritmo de classificação é implementado?
Como é que não causa consumo excessivo de memória?
O sort
comando UNIX pode classificar um arquivo muito grande como este:
sort large_file
Como o algoritmo de classificação é implementado?
Como é que não causa consumo excessivo de memória?
Respostas:
Os detalhes do algoritmo do comando UNIX Sort diz que o Unix Sort usa um algoritmo de classificação de mesclagem R-Way externo. O link fornece mais detalhes, mas basicamente divide a entrada em porções menores (que cabem na memória) e, em seguida, mescla cada porção no final.
O sort
comando armazena dados de trabalho em arquivos de disco temporários (geralmente em /tmp
).
-T
para especificar a temperatura dir
AVISO: este script inicia um shell por bloco, para arquivos realmente grandes, isso pode ser centenas.
Aqui está um roteiro que escrevi para esse propósito. Em uma máquina de 4 processadores, ele melhorou o desempenho de classificação em 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
Consulte também: " Classificando arquivos grandes mais rapidamente com um script de shell "
Não estou familiarizado com o programa, mas acho que é feito por meio de classificação externa (a maior parte do problema é mantida em arquivos temporários, enquanto uma parte relativamente pequena do problema é mantida na memória por vez). Ver The Art of Computer Programming, de Donald Knuth , vol. 3 Sorting and Searching, Section 5.4 para uma discussão muito aprofundada do assunto.
#!/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
Observe cuidadosamente as opções de classificação para acelerar o desempenho e entenda seu impacto em sua máquina e no problema. Os principais parâmetros do Ubuntu são
O questionador pergunta "Por que não há alto uso de memória?" A resposta para isso vem da história, as máquinas Unix mais antigas eram pequenas e o tamanho da memória padrão é pequeno. Ajuste isso o maior possível para sua carga de trabalho para melhorar muito o desempenho de classificação. Defina o diretório de trabalho para um local em seu dispositivo mais rápido que tenha espaço suficiente para armazenar pelo menos 1,25 * o tamanho do arquivo que está sendo classificado.
A memória não deve ser um problema - o sort já cuida disso. Se você quiser fazer o uso ideal de sua CPU multi-core, eu implementei isso em um pequeno script (semelhante a alguns que você pode encontrar na rede, mas mais simples / mais limpo do que a maioria deles;)).
#!/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*