การประมวลผลหลายตัวสำหรับ bash loop

ฉันมีสคริปต์ Bash ที่ไม่สำคัญซึ่งมีรูปแบบคร่าวๆ ต่อไปนี้:

# Initialization

<generate_data> | while read line; do

    # Run tests and filters on line

    if [ "$tests_pass" ]; then
        echo "$filtered_line"
    fi

done | sort <sort_option> | <consume_data>

# Finalization

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

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

มีเครื่องมือหรือคุณสมบัติที่สะดวกใด ๆ ที่ทำให้การดำเนินการกับสคริปต์สามารถกระจายไปยังกระบวนการต่าง ๆ โดยไม่กระทบต่อโครงสร้างโดยรวมของสคริปต์หรือไม่ ฉันไม่ทราบถึงฟีเจอร์ในตัวของ Bash แต่มีสิ่งหนึ่งที่มีประโยชน์อย่างแน่นอน


person epl    schedule 02.12.2019    source แหล่งที่มา
comment
ใช้ xargs เพียงพอหรือไม่   -  person gregory    schedule 02.12.2019
comment
unix.stackexchange.com/questions/103920/ แสดงตัวอย่างบางส่วนเกี่ยวกับการประมวลผลลูปแบบขนานใน bash หวังว่ามันจะมีประโยชน์สำหรับคุณ   -  person gzh    schedule 02.12.2019
comment
ขอบคุณ. ฉันได้อ่านหัวข้อนั้นแล้ว (103920) แต่ไม่พบสิ่งใดที่นำฉันไปสู่วิธีแก้ไขปัญหานี้ตามที่สร้างขึ้น คุณล่ะ?   -  person epl    schedule 02.12.2019
comment
แน่ใจนะว่าไม่ฟอร์ค?   -  person that other guy    schedule 02.12.2019
comment
@gregory นั่นจะทำงานคล้ายกับ GNU parallel ซึ่ง OP ไม่ต้องการ (แม้ว่า invoking an external command จะไม่แย่เท่ากับการรันลูปใน bash) @epl อาจเป็นไปได้ที่จะเพิ่มความเร็วตัวกรองของคุณให้เพียงพอโดยไม่ต้องหันไปใช้การคำนวณแบบขนาน ด้วยอินพุตและเอาต์พุตที่น้อยที่สุด บางคนอาจให้วิธีแก้ปัญหาแก่คุณที่นี่   -  person Socowi    schedule 02.12.2019
comment
@Socowi ฉันกำลังพัฒนาการใช้งานตรรกะตัวกรองให้เหมาะสมที่สุด ฉันไม่ต้องการความช่วยเหลือเป็นพิเศษกับงานนี้ แต่ประโยชน์ที่ได้รับจากการปรับปรุงดังกล่าวนั้นยังด้อยกว่าการใช้ฮาร์ดแวร์มากขึ้นควบคู่กันไปมาก ปัญหาในการ เรียกใช้คำสั่งภายนอก คือการขาดความสามารถในการจัดการโค้ดที่เกี่ยวข้องกับการย้ายลอจิกตัวกรองไปยังคำสั่งบางคำสั่งที่สามารถเรียกได้อย่างอิสระ   -  person epl    schedule 02.12.2019
comment
such an improvement applied by itself is far inferior to that from utilizing more hardware in parallel ฉันจะไม่นับมัน การวนซ้ำใน bash นั้นช้ามาก แม้ในแบบคู่ขนานก็มักจะไม่สามารถวิ่งเร็วกว่าภาษาอื่นหรือแม้แต่เครื่องมือพิเศษได้ ตัวอย่าง: ในการสร้างตัวเลขตั้งแต่ 1 ถึง 4'000'000 ฉันเปรียบเทียบ แนวทางต่อไปนี้ใน ควอดคอร์ หนึ่งลูปทุบตี (16.1 วินาที); สี่ลูปทุบตีแบบขนาน (5.2 วินาที) หนึ่ง awk วนซ้ำ (0.9 วินาที); และ seq (0.1 วินาที) โปรดทราบว่าลูปที่นี่ใช้เฉพาะบิวท์อินเท่านั้น หากคุณเรียกโปรแกรมภายนอกซ้ำ ๆ มันจะยิ่งแย่ลงไปอีก   -  person Socowi    schedule 02.12.2019
comment
@Sucowi ฉันเห็นด้วยแน่นอนว่า Bash นั้นช้า แต่การย้ายข้อมูลอยู่นอกเหนือขอบเขตที่แคบของหัวข้อนี้   -  person epl    schedule 02.12.2019
comment
ขออภัย ฉันไม่ต้องการกระตุ้นให้คุณใช้ภาษาที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ฉันแค่อยากเพิ่มประสิทธิภาพโค้ดทุบตีของคุณสำหรับตัวกรอง บ่อยครั้งที่สิ่งต่าง ๆ สามารถเขียนให้สั้นลงและมีประสิทธิภาพมากขึ้นโดยใช้เครื่องมือ (ทุบตี) ที่เหมาะสมสำหรับงาน คุณเพียงแค่ต้องรู้ว่าเครื่องมือที่เหมาะสมคืออะไร นั่นคือสิ่งที่ฉันชอบมากเกี่ยวกับการเขียนโปรแกรมแบบ bash มันเหมือนกับปริศนา   -  person Socowi    schedule 03.12.2019
comment
แล้วการใช้ Redis ล่ะ? คุณสามารถ LPUSH บรรทัด/บล็อกในรายการ Redis ได้อย่างง่ายดายและเริ่มโปรเซสเซอร์หลายตัวที่ BRPOP บล็อกออกจากรายการและ LPUSH ผลลัพธ์ไปยังรายการอื่น งานตัวประมวลผลสามารถทำงานได้ใน bash, Python หรือ C++ ในทุกเครื่องในเครือข่ายของคุณ   -  person Mark Setchell    schedule 05.12.2019
comment
ตัวอย่าง Redis... stackoverflow.com/a/22220082/2836621   -  person Mark Setchell    schedule 05.12.2019
comment
โดยทั่วไปแล้วมีแนวทางมากมายนับไม่ถ้วน แต่จุดประสงค์ของคำถามนั้นเกี่ยวข้องอย่างแคบมากกับการรักษาโครงสร้างโค้ดที่มีอยู่ในขณะที่เพิ่มการใช้กระบวนการแบบขนาน เหตุผลสำหรับหัวข้อนี้คือเพื่อทำความเข้าใจข้อจำกัดและความสามารถที่นำเสนอโดย bash และเครื่องมือที่เกี่ยวข้อง ไม่ใช่เพื่อระดมความคิดเกี่ยวกับกลยุทธ์ทั่วไปสำหรับการประมวลผลแบบขนาน ขอบคุณ.   -  person epl    schedule 07.12.2019
comment
@epl ฉันคิดว่ามันอาจจะง่ายกว่าที่จะตอบคำถามของคุณหากคุณกำหนดสิ่งที่คุณหมายถึงโดย bash และเครื่องมือที่เกี่ยวข้องอย่างเคร่งครัด หากไม่มีคำจำกัดความที่เข้มงวด ฉันคิดว่าคุณจะได้รับคำตอบ ซึ่งรวมถึงสิ่งที่ผู้ตอบคิดว่าเป็นการทุบตีและเครื่องมือที่เกี่ยวข้อง เช่น. ฉันจะพบว่า GNU Parallel เป็นเครื่องมือที่เกี่ยวข้องมาก - โดยพื้นฐานแล้ว เท่านั้น ก็สมเหตุสมผลหากเรียกใช้จากเชลล์ แต่ฉันรู้สึกว่าคุณไม่ได้รวม GNU Parallel ไว้ในคำจำกัดความของคุณ   -  person Ole Tange    schedule 07.12.2019
comment
คุณได้ทดลองกับ & และรอ $! แล้วหรือยัง? ฉันมักจะจัดเก็บผลลัพธ์แต่ละรายการไว้ในอาร์เรย์ รอให้ PID ทั้งหมดเสร็จสิ้น จากนั้นจึงเรียกใช้กระบวนการเรียงลำดับ/ขั้นสุดท้าย ฉันจะเขียนคำตอบพร้อมตัวอย่างสั้นๆ ในภายหลังหากคุณต้องการ   -  person Matthieu    schedule 07.12.2019
comment
@OleTange ยุติธรรมพอแล้ว ฉันกำลังคิดถึงเชลล์บิวด์อินและการเรียกใช้โปรแกรมที่น่าจะพร้อมใช้งานในสภาพแวดล้อม *Nix เป็นหลัก และโดยทั่วไปจะใช้เพื่อขยายเชลล์สคริปต์ให้เกินความสามารถดั้งเดิมของบิวด์อิน GNU Parallel จะถูกรวมไว้เป็นเครื่องมือที่เกี่ยวข้อง ฐานข้อมูล คิวข้อความ และเครื่องมือพิเศษไม่น่าจะรวมอยู่ด้วย อาจมีเครื่องมือต่างๆ เช่น AWK, Perl และ sed รวมอยู่ด้วย แต่การเขียนบล็อกโค้ดใหม่ในภาษาดังกล่าว แม้จะเป็นไปได้ แต่ก็อยู่นอกเหนือจุดประสงค์ของคำถาม ซึ่งค่อนข้างเป็นการอธิบายลักษณะขีดจำกัดและความสามารถของ Bash   -  person epl    schedule 07.12.2019
comment
@epl มันสมเหตุสมผลแล้วที่จะรวม Perl หากคุณอนุญาตโปรแกรม Perl ด้วย: คุณไม่สามารถใช้ Perl โดยไม่เขียนโปรแกรม Perl GNU Parallel เป็นโปรแกรม Perl และคุณสามารถรับประกันได้ว่าสคริปต์ของคุณจะพร้อมใช้งานโดยรวมไว้ในสคริปต์ด้วย --embed GNU Parallel ได้รับการทดสอบอย่างแข็งขันบนแพลตฟอร์มที่หลากหลาย และจะถูกมองว่าเป็นข้อบกพร่องหากไม่ได้ทำงานบนแพลตฟอร์ม *Nix ถ้า | ในขณะที่ .. เสร็จแล้ว | ไม่สามารถเปลี่ยนเป็น | ขนาน --ไปป์ .. | เพราะเห็นว่าเป็นการเขียนบล็อกใหม่ ผมจึงคิดว่าจะให้คำตอบที่ถูกต้องได้ยาก นอกจากไม่ ก็ไม่สามารถทำได้   -  person Ole Tange    schedule 07.12.2019


คำตอบ (2)


ปัญหาในการเรียกใช้คำสั่งภายนอกคือการขาดความสามารถในการจัดการโค้ดที่เกี่ยวข้องกับการย้ายลอจิกตัวกรองไปยังคำสั่งบางคำสั่งที่สามารถเรียกได้อย่างอิสระ

หากนั่นคือเหตุผลที่ไม่ใช้ GNU Parallel ดูเหมือนว่าคุณไม่ทราบถึง parallel --embed

--embed ถูกสร้างขึ้นมาอย่างแน่นอนเพราะผู้คนจำเป็นต้องมี GNU Parallel ในไฟล์เดียวกันกับโค้ดที่เหลือ

[output from parallel --embed]

myfilter() {
    while read line; do
      # Run tests and filters on line
      if [ "$tests_pass" ]; then
        echo "$filtered_line"
      fi
    done
}   
export -f myfilter

<generate_data> | parallel --pipe myfilter | sort <sort_option> | <consume_data>

สคริปต์ผลลัพธ์จะทำงานแม้ว่าจะไม่ได้ติดตั้ง GNU Parallel ก็ตาม

person Ole Tange    schedule 05.12.2019
comment
ฉันไม่ทราบถึง --embed ซึ่งดูเหมือนจะใหม่มาก และไม่รวมอยู่ในการแจกแจงล่าสุดด้วยซ้ำ แต่หากวัตถุประสงค์ของตัวเลือกนี้คือการสร้างสคริปต์ที่ทำงานโดยไม่ต้องพึ่งพา คำถามปัจจุบันจะไม่เกี่ยวข้องกันโดยสิ้นเชิงใช่หรือไม่ - person epl; 07.12.2019

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

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

เป็นเครื่องมือที่สะดวกใด ๆ ...

หากไม่มีคำจำกัดความของ 'เครื่องมือที่สะดวก' ของคุณซึ่งไม่สามารถตอบได้ โดยส่วนตัวแล้วฉันพบว่า parallel --pipe cmd สะดวก แต่อาจจะไม่เหมาะกับคำจำกัดความของคุณ

... หรือมีคุณลักษณะที่ทำให้การดำเนินการกับสคริปต์สามารถแจกจ่ายได้ในหลายกระบวนการโดยไม่กระทบต่อโครงสร้างโดยรวมของสคริปต์ ฉันไม่ทราบถึงฟีเจอร์ในตัวของ Bash แต่มีสิ่งหนึ่งที่มีประโยชน์อย่างแน่นอน

ไม่มี Bash ในตัว นี่เป็นเหตุผลหลักว่าทำไม GNU Parallel จึงมีตัวเลือก --pipe

ดูเหมือนว่าการใช้ | parallel --pipe myfilter | จะเข้ากับโครงสร้างโดยรวมของสคริปต์ได้ค่อนข้างดี

person Ole Tange    schedule 07.12.2019
comment
ฉันไม่คัดค้านการเรียกกระบวนการปฏิบัติการเช่นการเรียงลำดับ ความตั้งใจของความคิดเห็นที่คุณยกมาคือการดึงความสนใจไปที่ข้อจำกัดการรับรู้ที่ว่าคำสั่งที่จะส่งไปยัง Parallel จะต้องเป็นไฟล์ปฏิบัติการภายนอก ไม่ใช่ส่วนของสคริปต์ปัจจุบัน คุณท้าทายการรับรู้นี้หรือไม่? - person epl; 07.12.2019
comment
@epl เนื่องจากฉันทำอย่างนั้นในคำตอบอื่น ๆ (กล่าวคือส่งผ่านฟังก์ชันที่กำหนดไว้ในสคริปต์เดียวกัน - ไม่ใช่ไฟล์ปฏิบัติการ) ฉัน ทำ ท้าทายการรับรู้นี้ คุณสามารถตั้งชื่อแทนได้หากคุณใช้ env_parallel - person Ole Tange; 07.12.2019