Як команда UNIX сортування може сортувати дуже великий файл?


104

Команда UNIX sortможе сортувати дуже великий файл на зразок цього:

sort large_file

Як реалізується алгоритм сортування?

Чому це не викликає надмірного споживання пам’яті?


Це цікаво. Я не знаю, як це працює, але я здогадуюсь. Він, ймовірно, кладе перший символ кожного ключа у двійкове дерево, і коли відбувається зіткнення, він також використовує наступний символ ключа, тому він не зберігає більше ключа, ніж потрібно. Потім він може зберегти зміщення у файлі кожною клавішею, щоб він міг шукати назад та друкувати кожен рядок у порядку.
Зіфре

Насправді, @ayaz, це цікавіше, якщо ви не сортуєте файл на диску, а скоріше в трубі, оскільки це очевидно, що ви не можете просто зробити кілька пропусків над вхідними даними.
tvanfosson

3
Чому всі на ЗО відчувають себе так змушені весь час здогадуватися?

Ви можете зробити кілька проходів на вході - вам просто потрібно прочитати весь вхід, записати його на диск, а потім сортувати файл диска.

2
@Neil - з контексту здавалося очевидним, що він намагається сортувати вміст файлу, а не ім'я файлу (що для одного імені безглуздо). Я просто хотів вдосконалити питання, не змінюючи занадто сильно контексту, щоб він отримав відповіді замість низових записів через просту помилку.
tvanfosson

Відповіді:


111

У алгоритмічні деталі команди UNIX Сортування говорить Unix Сортування використовує алгоритм в злиття зовнішнього R-Way сортування. Посилання йде на більш детальну інформацію, але, по суті, вона ділить вхід на менші частини (які вписуються в пам'ять), а потім об'єднує кожну частину разом у кінці.


42

У sortкоманді зберігає робочі дані в тимчасових файлах диск (зазвичай /tmp).


20
використовувати, -Tщоб вказати temp dir
glenn jackman

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
Ви можете просто скористатись сортуванням - паралельне N за версією сортування GNU 8.11
jhclark

5
GNU coreutils 8.6 фактично
bdeonovic

1
Цей зробив для мене трюк. У мене є версія 8.4. Використовуючи сортування безпосередньо у файлі (190 мільйонів рядків) не було куди. Ця програма зробила це за трохи менше 4 хвилин
Sunil B

знову ж таки, ця відповідь не має нічого спільного з питанням
WattsInABox

2
Цей сценарій небезпечний. Моя машина Linux втратила відповідь після запуску сотень процесів сортування…
Yongwei Wu

11

Я не знайомий з програмою, але я думаю, що це робиться за допомогою зовнішнього сортування (більша частина проблеми зберігається у тимчасових файлах, тоді як відносно невелика частина проблеми зберігається в пам'яті за раз). Див. Дональд Кнут " Мистецтво комп'ютерного програмування", т. 3 Сортування та пошук, Розділ 5.4 для дуже поглибленого обговорення теми.


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

Я спробував використати comm для diff для файлів, що генеруються цим, і попереджає мене про те, що файли не сортуються.
ashishb

7

Погляньте уважно на варіанти сортування, щоб підвищити швидкість роботи та зрозуміти, що це впливає на вашу машину та проблеми. Основними параметрами Ubuntu є

  • Розташування тимчасових файлів -T ім'я_посібника
  • Обсяг пам’яті, який потрібно використовувати -SN% (N% усієї пам'яті, яку потрібно використовувати, тим більше, але краще, але уникайте надмірної підписки, яка спричиняє заміну диска. Ви можете використовувати її як -S 80%, щоб використовувати 80% доступної оперативної пам’яті, або "-S 2G" на 2 ГБ оперативної пам’яті.)

Запитуючий запитує: "Чому немає високого використання пам'яті?" Відповідь на це приходить з історії, старі машини Unix були невеликими, а розмір пам'яті за замовчуванням встановлено невеликим. Налаштуйте це якомога більше, щоб ваші навантаження були значно поліпшені. Встановіть робочий каталог на місце на вашому найшвидшому пристрої, в якому є достатньо місця для розміщення принаймні 1,25 * розміру файлу, який сортується.


спробувавши це на 2,5 Гб файлі, на коробці з 64 ГБ оперативної пам’яті з -S 80%, він фактично використовує цей повний відсоток, хоча весь файл менший від цього. чому так? навіть якщо він не використовує на місці сорт, який здається привабливим
Джозеф Гарвін

Можливо, сортування -S попередньо виділяє пам'ять для процесу сортування, перш ніж навіть прочитати вміст файлу.
Фред Ганнетт

-3

Пам'ять не повинна бути проблемою - сортування вже це бере на себе. Якщо ви хочете оптимально використовувати ваш багатоядерний процесор, я реалізую це в невеликому сценарії (подібний до деяких, який ви можете знайти в мережі, але простіший / чистіший, ніж більшість із них;)).

#!/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
Цікавий сценарій, але він нічого не дає відповіді на це питання.
Йоахім Зауер

5
split -b розділиться на байти, обрізаючи таким чином лінії у довільному положенні
ithkuil
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.