Score:3

ระบบไฟล์ "ทันเวลาพอดี" โดยใช้ inotifywait และ mkfifo

ธง ru

ฉันกำลังเขียนมิดเดิลแวร์ขั้นต้น โดยพื้นฐานแล้ว ฉันมีโค้ดเก่าที่ต้องเปิด 100,000 ไฟล์เพื่ออ่านอย่างเดียว โดยคาดว่าทั้งหมดจะอยู่ในโฟลเดอร์เดียว มันไม่เคยเขียน มันเป็นมัลติโพรเซสจึงสามารถลองเปิด ~30 ไฟล์พร้อมกันได้ วิธีเดิม ฉันจะต้องคัดลอกไฟล์ไปยังโฟลเดอร์นั้นจริงๆ (หรือใช้ลิงก์, NFS เป็นต้น) น่าสังเกตว่าฉันไม่มีความสามารถที่จะเปลี่ยนรหัสเก่านี้ - มันเป็นเพียงเลขฐานสอง

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

ดังนั้นฉันจึงนึกถึง mkfifo และ inotifywait แทนที่จะเป็นโฟลเดอร์ที่มีไฟล์ 100,000 ไฟล์ ฉันสามารถสร้างโฟลเดอร์ที่มีชื่อไพพ์ได้ 100,000 ไฟล์ จนถึงตอนนี้ดีมาก รหัสดั้งเดิมไปเปิดไฟล์โดยไม่รู้ว่าเป็นชื่อไพพ์ ปัญหาคือฉันไม่รู้ว่ารหัสดั้งเดิมจะเปิดไฟล์ตามลำดับใด (ดีใช่ไหม) ดังนั้นฉันต้องการทริกเกอร์ไปป์ที่มีชื่อ WRITE (จากรหัสใหม่แฟนซีของฉัน) เมื่อรหัสดั้งเดิมเข้าสู่การอ่าน ฉันไม่สามารถวางไข่ 100,000 เขียนและบล็อกทั้งหมดได้ ดังนั้นฉันคิดว่าเดี๋ยวก่อน - inotifywait เข้าท่า ทุกครั้งที่มรดกเปิดไปป์ มันจะทริกเกอร์เหตุการณ์การอ่าน ซึ่งสามารถใช้เพื่อวางไข่ผู้เขียนไปป์ในเบื้องหลัง ปัญหาคือ.. inotifywait ไม่ทริกเกอร์เหตุการณ์การอ่านจนกว่าผู้เขียนจะถูกวางไข่!

มีความคิดเกี่ยวกับวิธีแก้ปัญหานี้หรือไม่? โดยทั่วไป - ฉันต้องการสกัดกั้นการเปิดไฟล์ บล็อกสองสามร้อยมิลลิวินาทีในขณะที่ฉันดึงเนื้อหาของไฟล์ จากนั้นส่งคืนเนื้อหานั้น เป็นการดีที่ฉันไม่ต้องสร้างระบบไฟล์ FUSE แบบกำหนดเองเพื่อทำสิ่งนี้ .. มันเป็นเพียงไฟล์เปิดแบบอ่านอย่างเดียว ปัญหาคือต้องทำงานอย่างรวดเร็วและขนานกัน .. และฉันไม่รู้ว่าไฟล์ใดที่จะเปิดตามลำดับ ต้องเป็นวิธีที่รวดเร็วและสกปรก!

ขอบคุณล่วงหน้าสำหรับเวลาของทุกคน

แก้ไข - สำหรับรายละเอียดเพิ่มเติม โดยทั่วไปฉันมีรหัสเดิมที่ต้องการโหลดโฟลเดอร์ที่เต็มไปด้วยไฟล์ PNG ฉันต้องการให้ไฟล์ PNG เหล่านั้นมาจากเว็บเซิร์ฟเวอร์ที่ส่งคืนไฟล์ DICOM สิ่งนี้ต้องการการแปลงที่น่าเกลียด ฯลฯ รหัสการโหลด PNG ดั้งเดิมนั้นไม่ยืดหยุ่นมาก .. คาดว่าสิ่งเหล่านี้จะเป็นไฟล์ โดยพื้นฐานแล้วฉันต้องการสกัดกั้น fopen ของรหัสการโหลด PNG และเรียกใช้ bash pseudocode สี่บรรทัดต่อไปนี้ก่อน เดอะ $URL_FOR_DICOM ด้านล่างนี้ได้จาก $LADY_LOADED.png ชื่อไฟล์.

wget -q -O $LAZY_LOADED.dcm $URL_FOR_DICOM
dcmj2pnm --write-png $LAZY_LOADED.dcm $LAZY_LOADED.png
rm $LAZY_LOADED.dcm
แปลง $LAZY_LOADED.png -resize 1024x1024^ -ศูนย์ถ่วง -extent 1024x1024 $LAZY_LOADED.png

ดังนั้นเมื่อตัวโหลด PNG พยายามโหลด $LAZY_LOADED.png (ซึ่งจริงๆแล้วคือ FIFO) มันจะถูกเติมข้อมูลโดยใช้ข้อมูลด้านบน ซึ่งถูกกระตุ้นโดย inotify ฉันไม่สามารถทำสิ่งนี้ล่วงหน้าได้เนื่องจากชุดข้อมูลมีขนาดใหญ่ - เหมือนใกล้ถึง 0.5PB .. ดังนั้นฉันจึงไม่สามารถคัดลอกครั้งที่สองได้ ฉันต้องโหลดทันทีจากเว็บเซิร์ฟเวอร์

แก้ไข 2- เมื่อลองใช้ ifnotifywait กับไปป์ที่มีชื่อ มันจะบล็อกเหตุการณ์ใดๆ (รวมถึงเปิด เข้าถึง อ่าน.. ฯลฯ) จนกว่าไพพ์ที่มีชื่อจะเปิดให้เขียนและอ่าน... (เช่น ไม่มีทางตรวจพบว่าผู้อ่านพร้อม).. . ความคิด? ผู้ใช้รายอื่นมีปัญหาที่คล้ายกัน ที่นี่ ไม่มีทางออก :(

Score:3
ธง ca

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

คุณมีตัวเลือกที่ดีกว่าหลายตัว:

  • คัดลอกไฟล์ในตำแหน่งชั่วคราว
  • ที่ดียิ่งกว่านั้น แทนที่จะคัดลอก ให้ใช้ซอฟต์ลิงก์หรือฮาร์ดลิงก์
  • ส่งออกผ่านการเมาท์ NFS แบบอ่านอย่างเดียว

สุดท้ายนี้ โปรดทราบว่า inotify คือ ความพยายามที่ดีที่สุด กรอบงานเพื่อส่งมอบเหตุการณ์ไฟล์ การแจ้งเตือนภายใต้การโหลดจำนวนมากอาจสูญหายได้ โดยเฉพาะอย่างยิ่งหากใช้การเชื่อมโยงภาษาระดับสูง (เช่น: python)

แก้ไข: ดังนั้นคุณจึงต้องการสกัดกั้นการอ่านสำหรับการแปลงไฟล์แบบทันทีทันใดเมื่ออ่านจากไพพ์เปล่า รหัสดั้งเดิมของคุณจะบล็อก ดังนั้น แจ้งเตือน จะแสดงเหตุการณ์ READ หลังจากที่คุณเขียนบางอย่างลงในไพพ์เดียวกันเท่านั้น เพื่อหลีกเลี่ยงปัญหา คุณควรพยายามฟังเหตุการณ์ OPEN (แทนที่จะอ่าน) อีกทางเลือกหนึ่งคือการใช้ LD_PRELOAD เพื่อแทนที่ open() syscall แบบคลาสสิกด้วยเวอร์ชันที่กำหนดเองซึ่งจะแปลงไฟล์ตามต้องการ

ru flag
ขอบคุณสำหรับการตอบกลับที่รวดเร็วมาก - ปัญหาที่ฉันพบคือ..แหล่งที่มาไม่ใช่ไฟล์ แหล่งที่มาคือบริการบนเว็บที่ส่งคืนรูปภาพ ซึ่งจำเป็นต้องแปลง ปรับขนาด และครอบตัด ไม่มีทางที่ฉันจะมีพื้นที่เพียงพอในการคัดลอกทุกอย่าง (ในความเป็นจริง 300 เทราไบต์) .. ดังนั้นจำเป็นต้องทำ "ให้ทันเวลา" เป็นการดีที่ฉันสามารถเชื่อมโยง sym ไปยังไดเร็กทอรีต้นทางของบริการเว็บ .. แต่ .. สิ่งเหล่านี้อยู่ในเครื่องอื่นและอยู่ในรูปแบบไบนารีที่เป็นกรรมสิทธิ์ของผู้ขายเท่านั้นที่บริการเว็บเข้าถึงได้ ความคิดใด ๆ ??
ru flag
เพิ่มข้อมูลเพิ่มเติมด้านบนในคำถามหลัก - ขอบคุณอีกครั้ง
shodanshok avatar
ca flag
@mohotmoz ฉันได้แก้ไขคำตอบแล้วโดยเพิ่มรายละเอียดเพิ่มเติม
ru flag
ขอบคุณมาก! ดังนั้นเมื่อฉันลองฟังทุกเหตุการณ์ .. ก็ไม่มีอะไรเกิดขึ้นจนกระทั่งฉันเปิดท่อที่ปลายอีกด้านหนึ่ง เมื่อฉันลองเพียงแค่ OPEN events.. ก็ยังใช้งานไม่ได้ :( ไม่มีอะไรจนกว่าฉันจะเปิดไพพ์ที่ปลายอีกด้านแล้วเริ่มเขียน คนอื่นมีปัญหานี้: https://stackoverflow.com/questions/67639932/how-can-i-use-inotify-to-tell-when-a-named-pipe-is-opened
shodanshok avatar
ca flag
@mohotmoz ดังนั้นดูเหมือนว่า inotify ไม่ทำงานบนท่อที่ไม่ได้เชื่อมต่อ - ซึ่งเป็นผลลัพธ์ที่สมเหตุสมผล ถ้าเป็นเช่นนั้น และสมมติว่าคุณไม่สามารถแก้ไข Legacy Code ได้ คุณต้องเปิด (และเปิดต่อไป) ปลายท่อของคุณหรือโอเวอร์โหลดฟังก์ชัน open() ผ่าน LD_PRELOAD
Nonny Moose avatar
gb flag
คุณนำเสนอแนวคิด LD_PRELOAD ไว้เป็นความคิดภายหลัง แต่นี่อาจเป็นวิธีที่ควรไปที่นี่ ง่ายกว่าการพยายามทำสำเนาให้ทันเวลาอย่างแน่นอน

โพสต์คำตอบ

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