Làm cách nào mà lệnh sắp xếp UNIX có thể sắp xếp một tệp rất lớn?


104

Lệnh UNIX sortcó thể sắp xếp một tệp rất lớn như thế này:

sort large_file

Thuật toán sắp xếp được thực hiện như thế nào?

Làm thế nào để nó không gây tiêu thụ quá nhiều bộ nhớ?


Hay đấy. Tôi thực sự không biết nó hoạt động như thế nào, nhưng tôi có một phỏng đoán. Nó có thể đặt ký tự đầu tiên của mỗi khóa vào cây nhị phân và khi có va chạm, nó cũng sử dụng ký tự tiếp theo của khóa, vì vậy nó không lưu nhiều khóa hơn mức cần thiết. Sau đó, nó có thể lưu một phần bù vào tệp với mỗi phím để nó có thể tìm kiếm lại và in từng dòng theo thứ tự.
Zifre

Trên thực tế, @ayaz sẽ thú vị hơn nếu bạn không sắp xếp tệp trên đĩa mà là trong một đường ống vì điều đó cho thấy rõ ràng rằng bạn không thể đơn giản thực hiện nhiều lần chuyển dữ liệu đầu vào.
tvanfosson

3
Tại sao mọi người trên SO luôn cảm thấy bị thôi thúc phải đoán?

Bạn có thể thực hiện nhiều lần trên dữ liệu đầu vào - bạn chỉ cần đọc tất cả dữ liệu đầu vào, ghi dữ liệu vào đĩa và sau đó sắp xếp tệp đĩa.

2
@Neil - từ ngữ cảnh rõ ràng là anh ta đang cố gắng sắp xếp nội dung của tệp chứ không phải tên tệp (đối với một tên là vô nghĩa). Tôi chỉ muốn cải thiện câu hỏi mà không thay đổi ngữ cảnh quá nhiều để nó nhận được câu trả lời thay vì phản đối vì một sai lầm đơn giản.
tvanfosson

Câu trả lời:


111

Các chi tiết thuật toán của UNIX Sắp xếp lệnh nói Unix Sắp xếp sử dụng một ngoại R-Way merge thuật toán sắp xếp. Liên kết đi vào chi tiết hơn, nhưng về bản chất, nó chia dữ liệu đầu vào thành các phần nhỏ hơn (phù hợp với bộ nhớ) và sau đó kết hợp từng phần lại với nhau ở cuối.


42

Các sortcửa hàng lệnh dữ liệu trong các tập tin đĩa tạm thời làm việc (thường là trong /tmp).


20
sử dụng -Tđể xác định thư mục temp
glenn Jackman

12

CẢNH BÁO: Tập lệnh này bắt đầu một trình bao cho mỗi đoạn, đối với các tệp thực sự lớn, con số này có thể là hàng trăm.


Đây là một kịch bản tôi đã viết cho mục đích này. Trên máy 4 bộ xử lý, nó đã cải thiện 100% hiệu suất sắp xếp!

#! /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

Xem thêm: " Sắp xếp các tệp lớn nhanh hơn với tập lệnh shell "


35
Bạn chỉ có thể sử dụng N loại --parallel như các phiên bản loại GNU 8.11
jhclark

5
GNU coreutils 8.6 thực sự
bdeonovic

1
Điều này đã làm một mẹo cho tôi. Tôi có phiên bản sắp xếp 8,4. Sử dụng sắp xếp trực tiếp trên tệp (190 triệu dòng) sẽ không đi đến đâu. Chương trình này đã làm được điều đó chỉ với chưa đầy 4 phút
Sunil B

một lần nữa, câu trả lời này không có gì để làm với các câu hỏi
WattsInABox

2
Kịch bản này nguy hiểm. Máy tính của tôi Linux mất phản ứng sau khi tung ra hàng trăm quá trình loại ...
Yongwei Wu

11

Tôi không quen thuộc với chương trình nhưng tôi đoán nó được thực hiện bằng cách sắp xếp bên ngoài (hầu hết sự cố được lưu giữ trong các tệp tạm thời trong khi một phần tương đối nhỏ của sự cố được lưu trong bộ nhớ tại một thời điểm). Xem Nghệ thuật Lập trình Máy tính của Donald Knuth , Vol. 3 Sắp xếp và Tìm kiếm, Phần 5.4 để thảo luận sâu hơn về chủ đề này.


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

Thật tuyệt vời. Không biết rằng có một gói song song! Sắp xếp thời gian được cải thiện hơn 50% sau khi sử dụng ở trên. Cảm ơn.
xbsd

Tôi đã cố gắng sử dụng comm cho diff trên các tệp được tạo bởi điều này và nó cho tôi cảnh báo rằng các tệp không được sắp xếp.
ashishb

7

Xem xét cẩn thận các tùy chọn sắp xếp để tăng tốc hiệu suất và hiểu tác động của nó đối với máy và sự cố của bạn. Các thông số chính trên Ubuntu là

  • Vị trí của các tệp tạm thời -T directory_name
  • Dung lượng bộ nhớ sử dụng -SN% (N% của tất cả bộ nhớ sử dụng, càng nhiều càng tốt nhưng tránh đăng ký quá mức gây hoán đổi sang đĩa. Bạn có thể sử dụng nó như "-S 80%" để sử dụng 80% RAM khả dụng, hoặc "-S 2G" cho RAM 2 GB.)

Người hỏi đặt câu hỏi "Tại sao không sử dụng bộ nhớ cao?" Câu trả lời cho điều đó đến từ lịch sử, các máy unix cũ hơn nhỏ và kích thước bộ nhớ mặc định được đặt nhỏ. Điều chỉnh điều này càng lớn càng tốt để khối lượng công việc của bạn cải thiện đáng kể hiệu suất sắp xếp. Đặt thư mục làm việc vào một nơi trên thiết bị nhanh nhất của bạn có đủ dung lượng để chứa ít nhất 1,25 * kích thước của tệp đang được sắp xếp.


hãy thử điều này trên tệp 2,5 GB, trên hộp có RAM 64GB với -S 80%, nó thực sự đang sử dụng phần trăm đầy đủ đó, mặc dù toàn bộ tệp nhỏ hơn thế. tại sao vậy? ngay cả khi nó không sử dụng một loại tại chỗ có vẻ vô cớ
Joseph Garvin

Có thể sắp xếp -S phân bổ trước bộ nhớ cho quá trình sắp xếp trước khi đọc nội dung của tệp.
Fred Gannett

-3

Bộ nhớ không phải là một vấn đề - sắp xếp đã giải quyết vấn đề đó. Nếu bạn muốn sử dụng tối ưu CPU đa lõi của mình, tôi đã triển khai phần này trong một tập lệnh nhỏ (tương tự như một số bạn có thể tìm thấy trên mạng, nhưng đơn giản hơn / sạch hơn hầu hết những cái đó;)).

#!/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
Kịch bản thú vị, nhưng nó không có gì để trả lời câu hỏi này.
Joachim Sauer

5
chia -b sẽ chia bằng byte, do đó cắt bỏ các dây chuyền tại một vị trí tùy ý
ithkuil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.