การสร้างสตรีมเอาต์พุตเดี่ยวจากสามสตรีมอื่นที่สร้างแบบขนาน


10

ฉันมีข้อมูลสามชนิดที่มีรูปแบบต่างกัน สำหรับแต่ละชนิดข้อมูลมีสคริปต์ Python ที่แปลงเป็นรูปแบบรวมเป็นหนึ่งเดียว

สคริปต์ Python นี้ช้าและ CPU ที่ถูกผูกไว้ (เพื่อหลักเดียวในเครื่องแบบ multi-core) ดังนั้นฉันต้องการที่จะทำงานสามกรณีของมัน - หนึ่งสำหรับแต่ละชนิดข้อมูล - sortและรวมการส่งออกของพวกเขาจะผ่านมันเข้าไป โดยทั่วไปเทียบเท่ากับสิ่งนี้:

{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n

แต่ด้วยสามสคริปต์ที่ทำงานในแบบคู่ขนาน

ฉันพบคำถามนี้ที่ GNU splitถูกใช้เพื่อปัดเศษสตรีม stdout บางส่วนระหว่าง n อินสแตนซ์ของสคริปต์ที่จัดการสตรีม

จากหน้าแยกคน:

-n, --number=CHUNKS
          generate CHUNKS output files.  See below
CHUNKS  may be:
 N       split into N files based on size of input
 K/N     output Kth of N to stdout
 l/N     split into N files without splitting lines
 l/K/N   output Kth of N to stdout without splitting lines
 r/N     like 'l'  but  use  round  robin  distributio

ดังนั้นr/Nคำสั่งหมายถึง " ไม่มีเส้นแยก "

จากสิ่งนี้ดูเหมือนว่าทางออกต่อไปนี้ควรจะเป็นไปได้:

split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF

choose_scriptสิ่งนี้ทำที่ไหน:

#!/bin/bash
{ read x; ./handle_$x.py; }

น่าเสียดายที่ฉันเห็นบางบรรทัดแทรกเข้ามาและมีการขึ้นบรรทัดใหม่ที่ไม่ควรมี

ตัวอย่างเช่นถ้าฉันแทนที่สคริปต์ Python ของฉันด้วยสคริปต์ทุบตีง่ายๆที่ทำสิ่งนี้:

#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;

.

#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;

.

#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;

ฉันเห็นผลลัพธ์นี้:

1-8394

2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981

สิ่งนี้น่ารำคาญ - จากหน้าดึงข้อมูลที่ฉันวางไว้ด้านบนมันควรรักษาความสมบูรณ์ของบรรทัด

เห็นได้ชัดว่าใช้งานได้ถ้าฉันลบ-uอาร์กิวเมนต์ แต่แล้วมันจะถูกบัฟเฟอร์และฉันจะใช้หน่วยความจำไม่เต็มเพราะบัฟเฟอร์ผลลัพธ์ทั้งหมดยกเว้นสคริปต์ตัวใดตัวหนึ่ง

หากใครมีข้อมูลเชิงลึกที่นี่มันจะได้รับการชื่นชมอย่างมาก ฉันออกไปจากที่นี่


บางคนใน #bash บน freenode แนะนำว่าฉันวางไข่ทั้งสามกระบวนการและทำให้พวกมันเป็นพื้นหลังเขียนไปยัง FD ที่กำหนดเองจากนั้นวนรอบ FDs เหล่านั้นและอ่านบรรทัดสำหรับพวกเขา ฉันยังได้รับคำสั่งให้มองดูcoprocบิวอินในทุบตีแม้ว่าฉันจะไม่เห็นว่ามันใช้งานได้จริง
Cera

1
คุณต้องทำโดยไม่ใช้ไฟล์กลางหรือไม่? คุณทำjob1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3ไม่ได้เหรอ
กัส

คำตอบ:


2

ลองใช้ตัวเลือก -u ของ GNU ขนาน

echo "1\n2\n3" | parallel -u -IX ./handle_X.sh

สิ่งนี้จะทำงานในแบบขนานโดยไม่บัฟเฟอร์ทั้งหมดของกระบวนการใด ๆ


ฉันสับสนนิดหน่อย - XในการIXบอก-Iว่า X จะเป็นธงแทนหรือใช้-Xธงซึ่งดูเหมือนจะมีความหมายที่เกี่ยวข้องหรือไม่
Cera

ฮึ่ม ฉันกำลังทำสิ่งนี้: parallel -u -X ./handle_{}.sh ::: "1" "2" "3"และโชคไม่ดีที่ฉันยังคงเห็นบาง mangling เอาท์พุท
Cera

ก่อนหน้านี้: คุณสามารถใช้งานparallel -u ./handle_{}.shได้ แต่ฉันต้องการเปลี่ยนเนื่องจากการจัดฟันยังมีความหมายของการรวมคำสั่งเข้าด้วยกัน (เช่นในคำถามของคุณ)
flowblok

ดูเหมือนว่าจะทำงานให้ฉัน grep ของฉันไม่ได้รับ mangling ใด ๆ : pastie.org/5113187 (คุณกำลังใช้สคริปต์ทุบตีทดสอบหรือสคริปต์ Python จริง ๆ ของคุณหรือไม่)
flowblok

ปัญหาคือว่ามันไม่ได้ทำอะไรขนานกัน ฉันใช้สคริปต์ทุบตี - pastie.org/5113225
Cera

2

ลอง:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py

หากhandle_1.pyใช้ชื่อไฟล์:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

คุณไม่ต้องการเอาท์พุทมิกซ์ดังนั้นอย่าใช้ -u

หากคุณต้องการเก็บคำสั่งซื้อ (ดังนั้นผลลัพธ์ handle_1 ทั้งหมดจะอยู่ก่อน handle_2 และคุณอาจหลีกเลี่ยงการเรียงลำดับ):

parallel -k  ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

หากคุณยังต้องการเรียงมันคุณสามารถจัดเรียงและใช้ประโยชน์ขนานsort -mกันได้:

parallel --files "./handle_{1}.py {2} | sort -n"  ::: 1 2 3 ::: files* | parallel -j1 -X sort -m

ตั้งค่า $ TMPDIR เป็น dir ที่ใหญ่พอที่จะเก็บเอาท์พุท


1
ฉันต้องการเอาท์พุท 'มิกซ์' - ฉันแค่ต้องการตรวจสอบให้แน่ใจว่าทุกบรรทัดในเอาต์พุตสุดท้ายเป็นหนึ่งบรรทัดจากหนึ่งในกระบวนการย่อย ถ้าฉันไม่มิกซ์มันระบบจะหน่วยความจำไม่เพียงพอที่จะสตรีม stdout ที่ยังไม่ถูกพิมพ์ออกมา
Cera

ด้วย GNU Parallel คุณจะไม่มีหน่วยความจำไม่เพียงพอ: ไม่บัฟเฟอร์ในหน่วยความจำ ทำไมคุณคิดว่าบัฟเฟอร์ในหน่วยความจำ
Ole Tange

2

บางทีฉันอาจจะพลาดบางสิ่ง แต่คุณทำไม่ได้:

(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n

หากคุณต้องการให้บรรทัดจากแต่ละกระบวนการไม่ต้องถูกอินเตอร์ลีลอาจจะง่ายกว่าเพื่อให้แน่ใจว่ากระบวนการเขียนตัวเองอย่างเต็มที่และอาจปิดใช้งานการบัฟเฟอร์เอาต์พุตเนื่องจากwrites ไปยังไพพ์รับประกันว่าจะเป็นอะตอมตราบใดที่มันไม่ใหญ่กว่าPIPE_BUF. ตัวอย่างเช่นคุณสามารถทำให้แน่ใจว่ามันไม่บัฟเฟอร์การใช้งานการส่งออกอาหารstdioและโทรfflushหรือสิ่งที่เทียบเท่าอยู่ในpythonหลังจากที่หนึ่งหรือไม่กี่บรรทัดได้รับการเขียน

หากคุณไม่สามารถแก้ไขสคริปต์ python คุณสามารถทำได้:

lb() { grep --line-buffered '^'; }

(ด้วย GNU grep) หรือ:

lb() while IFS= read -r l; do printf '%s\n' "$l"; done

(ดูหมายเหตุในความคิดเห็นด้านล่างหากสิ่งที่เอาต์พุตคำสั่งไม่ใช่ข้อความ)

และทำ:

(./handle_1.py | lb & ./handle_2.py | lb & ./handle_3.py | lb) | sort -n

อีกทางเลือกหนึ่งในการหลีกเลี่ยงlbกระบวนการทั้งสามนี้คือการมีสามไพพ์ต่อคำสั่งเดียวที่ใช้select/ pollเพื่อดูว่ามีเอาต์พุตบางตัวมาจากไหนและฟีดมันเป็นsortแบบอิงบรรทัด แต่ใช้การเขียนโปรแกรมเล็กน้อย


คุณต้องมีwaitในฉันคิดว่า
Derobert

1
ไม่ยกเว้นบางโปรแกรมปิด stdout ก่อนที่จะออกเพราะไปป์และsort -nจะยังคงอยู่จนกว่าโปรแกรมทั้งหมดที่เปิด fd จะออกจากโปรแกรม
Stéphane Chazelas

แน่นอนฉันทดสอบคุณถูกต้อง
Derobert

ไม่ฉันยังได้รับเอาต์พุตที่ยุ่งเหยิง เส้นผสมกันและ interleaved
Cera

1
ตกลง @Calesales ดูคำตอบที่อัปเดตของฉัน
Stéphane Chazelas

1

คำตอบของ Flowbok คือทางออกที่ถูกต้อง ผิดปรกติเอาต์พุตของ GNU parallelจะยุ่งเหยิงถ้ามันส่งออกไปยังไฟล์โดยตรง - แต่ไม่ใช่ถ้ามันไปที่ tty

โชคดีที่script -cมีการเลียนแบบ tty

ยังมีสคริปต์สามตัว:

#!/bin/bash
# handle_1.sh
while true; do echo "1-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_2.sh
while true; do echo "2-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_3.sh
while true; do echo "3-$RANDOM$RANDOM$RANDOM$RANDOM"; done

จากนั้นมีไฟล์ที่สรุปการโทรเป็นแบบขนาน:

#!/bin/bash
# run_parallel.sh
parallel -u -I N ./handle_N.sh ::: "1" "2" "3"

แล้วฉันจะเรียกมันว่า:

script -c ./run_parallel > output

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

พฤติกรรมที่แปลกประหลาดจากparallel- ฉันอาจยื่นรายงานข้อผิดพลาด

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