คำสั่ง UNIX sort จัดเรียงไฟล์ขนาดใหญ่มากได้อย่างไร


105

sortคำสั่งUNIX สามารถจัดเรียงไฟล์ที่มีขนาดใหญ่มากดังนี้:

sort large_file

อัลกอริทึมการจัดเรียงใช้งานอย่างไร

เหตุใดจึงไม่ทำให้สิ้นเปลืองหน่วยความจำมากเกินไป?


เรื่องนี้น่าสนใจ ฉันไม่รู้จริงๆว่ามันทำงานอย่างไร แต่ฉันเดาได้ มันอาจทำให้อักขระตัวแรกของแต่ละคีย์เป็นไบนารีทรีและเมื่อมีการชนกันก็จะใช้อักขระถัดไปของคีย์ด้วยดังนั้นจึงไม่บันทึกคีย์มากกว่าที่จำเป็น จากนั้นอาจบันทึกออฟเซ็ตลงในไฟล์ด้วยแต่ละคีย์เพื่อให้สามารถค้นหาและพิมพ์แต่ละบรรทัดตามลำดับ
Zifre

จริงๆแล้ว @ayaz น่าสนใจกว่าถ้าคุณไม่ได้จัดเรียงไฟล์บนดิสก์ แต่อยู่ในไพพ์เนื่องจากเห็นได้ชัดว่าคุณไม่สามารถส่งผ่านข้อมูลอินพุตหลาย ๆ
tvanfosson

3
ทำไมทุกคนใน SO ถึงรู้สึกถูกกระตุ้นให้เดาตลอดเวลา?

คุณสามารถป้อนข้อมูลได้หลายครั้ง - คุณเพียงแค่ต้องอ่านอินพุตทั้งหมดเขียนลงดิสก์แล้วเรียงไฟล์ดิสก์

2
@Neil - จากบริบทดูเหมือนชัดเจนว่าเขาพยายามจัดเรียงเนื้อหาของไฟล์ไม่ใช่ชื่อไฟล์ (ซึ่งสำหรับชื่อเดียวไม่มีความหมาย) ฉันแค่อยากจะปรับปรุงคำถามโดยไม่เปลี่ยนบริบทมากเกินไปเพื่อที่จะได้รับคำตอบแทนการโหวตลงคะแนนเพราะความผิดพลาดง่ายๆ
tvanfosson

คำตอบ:


112

ขั้นตอนรายละเอียดของคำสั่งเรียง UNIXกล่าวว่า Unix เรียงใช้ภายนอก R-Way ผสานขั้นตอนวิธีการเรียงลำดับ ลิงก์จะให้รายละเอียดเพิ่มเติม แต่โดยพื้นฐานแล้วจะแบ่งอินพุตออกเป็นส่วนเล็ก ๆ (ที่พอดีกับหน่วยความจำ) จากนั้นจะรวมแต่ละส่วนเข้าด้วยกันในตอนท้าย



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
คุณสามารถใช้ sort --parallel N ได้ตั้งแต่ GNU sort เวอร์ชัน 8.11
jhclark

5
GNU coreutils 8.6 จริง
bdeonovic

1
อันนี้ทำเคล็ดลับสำหรับฉัน ฉันมีการเรียงลำดับเวอร์ชัน 8.4 การใช้การเรียงลำดับโดยตรงบนไฟล์ (190 ล้านบรรทัด) ไม่ได้อยู่ที่ไหน โปรแกรมนี้ใช้เวลาเพียงไม่ถึง 4 นาที
Sunil B

อีกครั้งคำตอบนี้ไม่เกี่ยวข้องกับคำถาม
WattsInABox

2
คริปนี้อันตราย เครื่อง Linux ของฉันสูญเสียการตอบสนองหลังจากเปิดตัวกระบวนการเรียงลำดับหลายร้อยรายการ…
Yongwei Wu

11

ฉันไม่คุ้นเคยกับโปรแกรม แต่ฉันคิดว่ามันทำโดยการจัดเรียงภายนอก (ปัญหาส่วนใหญ่เกิดขึ้นในไฟล์ชั่วคราวในขณะที่ปัญหาส่วนเล็ก ๆ จะถูกเก็บไว้ในหน่วยความจำในแต่ละครั้ง) ดูThe Art of Computer Programming ของ Donald Knuth , Vol. 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 เพื่อความแตกต่างกับไฟล์ที่สร้างขึ้นโดยสิ่งนี้และทำให้ฉันเตือนว่าไฟล์ไม่ได้เรียงลำดับ
ashishb

7

ดูตัวเลือกของการจัดเรียงอย่างละเอียดเพื่อเพิ่มความเร็วในการทำงานและทำความเข้าใจว่ามีผลกระทบต่อเครื่องและปัญหาของคุณ พารามิเตอร์สำคัญบน Ubuntu คือ

  • ตำแหน่งของไฟล์ชั่วคราว -T directory_name
  • จำนวนหน่วยความจำที่จะใช้ -SN% (N% ของหน่วยความจำทั้งหมดที่จะใช้ยิ่งดี แต่หลีกเลี่ยงการสมัครสมาชิกที่ทำให้เกิดการสลับไปยังดิสก์คุณสามารถใช้มันเช่น "-S 80%" เพื่อใช้ 80% ของ RAM ที่มี หรือ "-S 2G" สำหรับ RAM 2 GB)

ผู้ถามถามว่า "ทำไมไม่ใช้หน่วยความจำสูง" คำตอบนั้นมาจากประวัติเครื่องยูนิกซ์รุ่นเก่ามีขนาดเล็กและขนาดหน่วยความจำเริ่มต้นถูกตั้งค่าให้เล็ก ปรับสิ่งนี้ให้ใหญ่ที่สุดสำหรับปริมาณงานของคุณเพื่อปรับปรุงประสิทธิภาพการจัดเรียงอย่างมาก ตั้งค่าไดเร็กทอรีการทำงานเป็นตำแหน่งบนอุปกรณ์ที่เร็วที่สุดของคุณซึ่งมีพื้นที่เพียงพอสำหรับจัดเรียงขนาดไฟล์อย่างน้อย 1.25 *


ลองใช้ไฟล์ 2.5GB บนกล่องที่มี RAM 64GB พร้อม -S 80% มันใช้เปอร์เซ็นต์เต็มแม้ว่าไฟล์ทั้งหมดจะเล็กกว่านั้นก็ตาม ทำไมเป็นอย่างนั้น? แม้ว่าจะไม่ใช้การจัดเรียงแบบแทนที่ดูเหมือนจะไม่มีเหตุผลก็ตาม
โจเซฟการ์วิน

อาจจะเรียงลำดับ -S จัดสรรหน่วยความจำไว้ล่วงหน้าสำหรับกระบวนการเรียงลำดับก่อนที่จะอ่านเนื้อหาของไฟล์
Fred Gannett

-3

หน่วยความจำไม่ควรมีปัญหา - sort ดูแลอยู่แล้ว หากคุณต้องการใช้ซีพียูแบบมัลติคอร์ให้เกิดประโยชน์สูงสุดฉันได้ใช้สิ่งนี้ในสคริปต์ขนาดเล็ก (คล้ายกับบางตัวที่คุณอาจพบในเน็ต แต่เรียบง่าย / สะอาดกว่าส่วนใหญ่;))

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

5
Split -b จะแบ่งตามไบต์ดังนั้นจึงตัดทอนเส้นที่ตำแหน่งโดยพลการ
ithkuil
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.