UNIX sort 명령은 어떻게 매우 큰 파일을 정렬 할 수 있습니까?


104

UNIX sort명령은 다음과 같이 매우 큰 파일을 정렬 할 수 있습니다.

sort large_file

정렬 알고리즘은 어떻게 구현됩니까?

과도한 메모리 소비를 일으키지 않는 이유는 무엇입니까?


이건 재미 있네. 어떻게 작동하는지 잘 모르겠지만 추측이 있습니다. 아마도 각 키의 첫 번째 문자를 이진 트리에 넣고 충돌이 발생하면 키의 다음 문자도 사용하므로 필요한 것보다 더 많은 키를 저장하지 않습니다. 그런 다음 각 키를 사용하여 파일에 오프셋을 저장하여 순서대로 각 줄을 검색하고 인쇄 할 수 있습니다.
Zifre

실제로 @ayaz는 디스크에서 파일을 정렬하지 않고 파이프로 정렬하는 것이 더 흥미 롭습니다. 입력 데이터에 대해 여러 번 통과 할 수 없다는 것이 분명해지기 때문입니다.
tvanfosson

3
왜 모든 사람들이 항상 추측해야 할 충동을 느끼는가?

입력에 대해 여러 단계를 수행 할 수 있습니다. 모든 입력을 읽고 디스크에 쓴 다음 디스크 파일을 정렬하기 만하면됩니다.

2
@Neil-문맥에서 그가 파일 이름이 아닌 파일의 내용을 정렬하려고하는 것이 분명해 보였습니다 (하나의 이름은 의미가 없습니다). 단순한 실수로 인해 비추천 대신 답변을 얻을 수 있도록 컨텍스트를 너무 많이 변경하지 않고 질문을 개선하고 싶었습니다.
tvanfosson

답변:


111

UNIX Sort 명령알고리즘 세부 정보에 따르면 Unix Sort는 외부 R-Way 병합 정렬 알고리즘을 사용합니다. 링크는 더 자세히 설명하지만 본질적으로 입력을 더 작은 부분 (메모리에 맞는)으로 나누고 마지막에 각 부분을 병합합니다.


42

sort명령은 작업 데이터를 임시 디스크 파일 (일반적으로 /tmp)에 저장합니다.


20
사용하는 -T임시 디렉토리를 지정
글렌 잭맨

12

경고 : 이 스크립트는 청크 당 하나의 셸을 시작합니다. 정말 큰 파일의 경우 수백 개가 될 수 있습니다.


여기에 제가이 목적으로 작성한 스크립트가 있습니다. 4 프로세서 시스템에서 정렬 성능이 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

참조 : " 쉘 스크립트를 사용하여 대용량 파일을 더 빠르게 정렬 "


35
GNU 정렬 버전 8.11
jhclark 2011 년

5
실제로 GNU coreutils 8.6
bdeonovic 2014-10-17

1
이것은 나를 위해 트릭을했습니다. 8.4 버전이 있습니다. 파일에서 직접 정렬 (1 억 9 천만 줄)을 사용하는 것은 아무데도 미치지 못했습니다. 이 프로그램은 4 분도
안되는

다시,이 답변이 문제와는 아무 상관이 없다
WattsInABox

2
이 스크립트는 위험합니다. 내 리눅스 머신은 ... 정렬 프로세스의 수백을 실행 한 후 응답을 잃었다
Yongwei 우에게


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

이것은 훌륭합니다. 병렬 패키지가 있다는 것을 몰랐습니다! 위의 사용 후 정렬 시간이 50 % 이상 향상되었습니다. 감사.
xbsd

나는 이것에 의해 생성 된 파일에 대한 diff를 위해 comm을 사용하려고 시도했으며 파일이 정렬되지 않았다는 경고를 받았습니다.
ashishb

7

성능을 높이기 위해 정렬 옵션을주의 깊게 살펴보고 이것이 기계 및 문제에 미치는 영향을 이해하십시오. Ubuntu의 주요 매개 변수는 다음과 같습니다.

  • 임시 파일의 위치 -T directory_name
  • 사용할 메모리 양 -SN % (사용할 모든 메모리의 N %, 더 많을수록 좋지만 디스크로 스와핑을 일으키는 초과 구독을 피하십시오. 사용 가능한 RAM의 80 %를 사용하려면 "-S 80 %"와 같이 사용할 수 있습니다. 또는 2GB RAM의 경우 "-S 2G".)

질문자는 "왜 메모리 사용량이 많지 않습니까?"라고 묻습니다. 이에 대한 답은 역사에서 비롯된 것입니다. 구형 유닉스 머신은 작았고 기본 메모리 크기는 작게 설정되어 있습니다. 워크로드에 대해 가능한 한 크게 조정하여 정렬 성능을 크게 향상 시키십시오. 작업 디렉토리를 정렬중인 파일 크기의 최소 1.25 *를 저장할 수있는 충분한 공간이있는 가장 빠른 장치의 위치로 설정하십시오.


2.5GB 파일, 64GB RAM (-S 80 % 포함) 상자에서이 작업을 시도하면 전체 파일이 그보다 작더라도 실제로 전체 비율을 사용하고 있습니다. 왜 그런 겁니까? 불필요한 것처럼 보이는 제자리 정렬을 사용하지 않더라도
Joseph Garvin

아마도 sort -S는 파일의 내용을 읽기 전에 정렬 프로세스를위한 메모리를 미리 할당합니다.
Fred Gannett

-3

메모리는 문제가되지 않아야합니다. sort는 이미 그것을 처리합니다. 멀티 코어 CPU를 최적으로 사용하려면 작은 스크립트로이를 구현했습니다 (인터넷에서 찾을 수있는 일부와 비슷하지만 대부분보다 간단하고 깔끔합니다.).

#!/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
흥미로운 스크립트이지만이 질문에 대한 답은 없습니다.
Joachim Sauer 2011 년

5
split -b는 바이트 단위로 분할되므로 임의의 위치에서 줄이 잘립니다
ithkuil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.