ประสิทธิภาพของลูปเทียบกับการขยาย


9

ต้องการคำแนะนำจากผู้เชี่ยวชาญในการเปรียบเทียบด้านล่าง:

ส่วนของรหัสโดยใช้ลูป:

for file in `cat large_file_list`
do
    gzip -d $file
done

ส่วนของรหัสโดยใช้การขยายอย่างง่าย:

gzip -d `cat large_file_list`

อันไหนจะเร็วกว่ากัน? ต้องจัดการกับชุดข้อมูลขนาดใหญ่


1
คำตอบที่ถูกต้องจะขึ้นอยู่กับระยะเวลาที่ใช้ในการเริ่มgzipระบบของคุณจำนวนไฟล์ในรายการไฟล์และขนาดของไฟล์เหล่านั้น
Kusalananda

รายการไฟล์จะมีไฟล์ประมาณ 1,000 - 10,000 ไฟล์ ขนาดแตกต่างกันจากบางกิโลไบต์ถึง 500 MB ฉันไม่ทราบว่าใช้เวลานานเท่าใดในการเริ่มgzipในระบบของฉัน ตรวจสอบวิธีการใด ๆ
Leon

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

Leon ดูที่ผลการทดสอบของฉัน: "huge-arglist" เร็วกว่า "loop" 20 เท่าในการตั้งค่าของฉัน

สำหรับสื่อที่มีความสุขระหว่างการเริ่มกระบวนการและความยาวบรรทัดคำสั่งให้ใช้สิ่งที่คล้ายกันxargs gzip -d < large_file_listแต่ระวังช่องว่างในชื่อไฟล์บางทีด้วยtr \\n \\0 large_file_list | xargs -0 gzip -d
w00t

คำตอบ:


19

ภาวะแทรกซ้อน

บางครั้งต่อไปนี้จะใช้งานได้:

gzip -d `cat large_file_list`

สามปัญหาคือ (ในbashและเชลล์คล้าย Bourne อื่น ๆ ):

  1. มันจะล้มเหลวหากชื่อไฟล์ใด ๆ มีแท็บที่ว่างหรืออักขระขึ้นบรรทัดใหม่ (สมมติ$IFSว่าไม่ได้มีการแก้ไข) นี้เป็นเพราะเปลือกแยกคำ

  2. นอกจากนี้ยังมีแนวโน้มที่จะล้มเหลวหากชื่อไฟล์ใด ๆ มีอักขระแบบแอคทีฟกลมอยู่ภายใน นี่เป็นเพราะเชลล์จะใช้การขยายชื่อพา ธกับรายการไฟล์

  3. นอกจากนี้ยังจะล้มเหลวถ้าชื่อไฟล์ที่เริ่มต้นด้วย-(ถ้าPOSIXLY_CORRECT=1ที่ใช้เฉพาะกับไฟล์แรก) หรือถ้าชื่อไฟล์ใด ๆ -ที่เป็น

  4. นอกจากนี้ยังจะล้มเหลวหากมีชื่อไฟล์มากเกินไปเพื่อให้พอดีกับบรรทัดคำสั่งเดียว

รหัสด้านล่างอาจมีปัญหาเช่นเดียวกับรหัสข้างต้น (ยกเว้นที่สี่)

for file in `cat large_file_list`
do
    gzip -d $file
done

ทางออกที่เชื่อถือได้

หากคุณlarge_file_listมีชื่อไฟล์หนึ่งชื่อต่อหนึ่งบรรทัดอย่างแน่นอนและไฟล์ที่เรียก-ว่าไม่ได้อยู่ในชื่อเดียวกันและคุณอยู่ในระบบ GNU ให้ใช้:

xargs -rd'\n' gzip -d -- <large_file_list

-d'\n'บอกxargsให้ถือว่าแต่ละบรรทัดของการป้อนข้อมูลเป็นชื่อไฟล์แยกต่างหาก

-rบอกxargsไม่ให้รันคำสั่งหากไฟล์อินพุตว่างเปล่า

--บอกว่าข้อโต้แย้งต่อไปนี้จะไม่ได้ที่จะถือว่าเป็นตัวเลือกแม้ว่าพวกเขาจะเริ่มต้นด้วยgzip อยู่คนเดียวจะยังคงได้รับการปฏิบัติเป็นแทนของไฟล์ที่เรียกว่า----

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


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

1
@Leon forวงวนนั้นจะช้าที่สุด อีกสองวิธีจะเร็วใกล้กันมาก
John1024

7
อย่าเพิกเฉยต่อปัญหาที่อาจเกิดขึ้น: คำถามมากมายที่ StackExchange ที่นี่เป็นเพราะการแยกคำหรือการขยายชื่อพา ธเกิดขึ้นกับคนที่ไม่ได้คาดหวัง
John1024

5
โปรดทราบว่ามีความหลากหลายในการอ่านไฟล์ด้วยxargs: อย่างน้อยรุ่น GNU มี--arg-fileตัวเลือก (แบบสั้น-a) ดังนั้นหนึ่งสามารถทำxargs -a large_file_list -rd'\n' gzip -d แทน อย่างมีประสิทธิภาพไม่มีความแตกต่างนอกเหนือจากความจริงที่ว่า<เป็นตัวดำเนินการของเชลล์และจะxargsอ่านจาก stdin (ซึ่งเชลล์ "ลิงก์" ไปยังไฟล์) ในขณะที่-aจะxargsเปิดไฟล์อย่างชัดเจน
Sergiy Kolodyazhnyy

2
terdon กล่าวไว้ในความคิดเห็นอื่นเกี่ยวกับการใช้parallelเพื่อเรียกใช้สำเนาหลายชุดgzipแต่xargsอย่างน้อย GNU หนึ่งชุดก็มี-Pสวิตช์สำหรับใช้ด้วย บนเครื่องมัลติคอร์ที่อาจสร้างความแตกต่าง แต่ก็เป็นไปได้ที่การบีบอัดจะเป็น I / O-bound อย่างสมบูรณ์
ilkkachu

12

ฉันสงสัยว่ามันจะสำคัญมาก

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

ลูปของฉันจะเป็นอย่างไร

while IFS= read -r name; do
    gunzip "$name"
done <file.list

สิ่งนี้จะทำให้ฉันสามารถแทรกคำสั่งสำหรับการประมวลผลข้อมูลหลังจากgunzipคำสั่ง ในความเป็นจริงแล้วขึ้นอยู่กับข้อมูลจริงและสิ่งที่ต้องทำกับมันมันอาจเป็นไปได้ในการประมวลผลโดยไม่ต้องบันทึกลงในไฟล์เลย:

while IFS= read -r name; do
    zcat "$name" | process_data
done <file.list

(โดยที่process_dataไปป์ไลน์บางตัวอ่านข้อมูลที่ไม่มีการบีบอัดจากอินพุตมาตรฐาน)

หากการประมวลผลข้อมูลใช้เวลานานกว่าการคลายการบีบอัดข้อมูลคำถามที่ว่าการวนซ้ำนั้นมีประสิทธิภาพมากขึ้นหรือไม่ไม่เกี่ยวข้อง

เป็นการดีที่ฉันต้องการที่จะไม่ทำงานกับรายการชื่อไฟล์ แต่และใช้รูปแบบชื่อไฟล์กลม ๆ แทนเช่นใน

for name in ./*.gz; do
    # processing of "$name" here
done

ที่./*.gzเป็นรูปแบบบางอย่างที่ตรงกับไฟล์ที่เกี่ยวข้อง วิธีนี้เราไม่ได้ขึ้นอยู่กับจำนวนไฟล์หรือตัวละครที่ใช้ในชื่อไฟล์ (อาจมีการขึ้นบรรทัดใหม่หรืออักขระช่องว่างอื่น ๆ หรือเริ่มต้นด้วยเครื่องหมายขีดคั่นเป็นต้น)

ที่เกี่ยวข้อง:


5

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

แต่ฉันต้องการเตือนกฎทองแห่งการเพิ่มประสิทธิภาพ : อย่าทำก่อนเวลาอันควร

  1. อย่าเพิ่มประสิทธิภาพของสิ่งนั้นก่อนที่คุณจะรู้ว่ามันเป็นปัญหา

    ส่วนนี้ของโปรแกรมใช้เวลานานหรือไม่? การคลายการบีบอัดไฟล์ขนาดใหญ่อาจเป็นไปได้และคุณจะต้องทำต่อไปดังนั้นมันอาจไม่ใช่คำตอบที่ง่ายนัก

  2. วัด. เป็นวิธีที่ดีที่สุดที่จะแน่ใจ

    คุณจะเห็นผลลัพธ์ด้วยตาของคุณเอง (หรือด้วยนาฬิกาจับเวลาของคุณ) และพวกเขาจะนำไปใช้กับสถานการณ์ของคุณซึ่งอาจไม่มีคำตอบแบบสุ่มบนอินเทอร์เน็ต ใส่สายพันธุ์ทั้งในสคริปต์และการทำงานและtime script1.sh time script2.sh(ทำเช่นนั้นกับรายการไฟล์บีบอัดที่ว่างเปล่าเพื่อวัดจำนวนเงินที่แน่นอนของค่าใช้จ่าย)


0

ดิสก์ของคุณเร็วแค่ไหน

สิ่งนี้ควรใช้ CPU ทั้งหมดของคุณ:

parallel -X gzip -d :::: large_file_list

ดังนั้นข้อ จำกัด ของคุณน่าจะเป็นความเร็วของดิสก์ของคุณ

คุณสามารถลองปรับด้วย-j:

parallel -j50% -X gzip -d :::: large_file_list

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

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