ฉันประสบความสำเร็จในการแก้ปัญหาของฉัน นี่คือรายละเอียดพร้อมคำอธิบายเผื่อว่าใครมีปัญหาคล้าย ๆ กันเจอหน้านี้ แต่ถ้าคุณไม่สนใจรายละเอียดนี่คือคำตอบสั้น ๆ :
ใช้ PTY.spawn ในลักษณะต่อไปนี้ (ด้วยคำสั่งของคุณเอง):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
และนี่คือคำตอบยาว ๆพร้อมรายละเอียดมากเกินไป:
ปัญหาที่แท้จริงดูเหมือนว่าหากกระบวนการไม่ได้ล้าง stdout อย่างชัดเจนสิ่งที่เขียนไปยัง stdout จะถูกบัฟเฟอร์แทนที่จะส่งจริงจนกว่ากระบวนการจะเสร็จสิ้นเพื่อลด IO ให้น้อยที่สุด ( เห็นได้ชัดว่าเป็นรายละเอียดการใช้งานของหลาย ๆ ไลบรารี C สร้างขึ้นเพื่อให้ทรูพุตขยายใหญ่สุดผ่าน IO ที่ไม่บ่อย) หากคุณสามารถปรับเปลี่ยนกระบวนการได้อย่างง่ายดายเพื่อให้ล้าง stdout เป็นประจำนั่นจะเป็นทางออกของคุณ ในกรณีของฉันมันเป็นเครื่องปั่นดังนั้นค่อนข้างน่ากลัวสำหรับ noob ที่สมบูรณ์เช่นตัวฉันเองในการแก้ไขแหล่งที่มา
แต่เมื่อคุณรันกระบวนการเหล่านี้จากเชลล์กระบวนการเหล่านี้จะแสดง stdout ไปยังเชลล์แบบเรียลไทม์และ stdout ดูเหมือนจะไม่ถูกบัฟเฟอร์ มันบัฟเฟอร์เมื่อถูกเรียกจากกระบวนการอื่นที่ฉันเชื่อเท่านั้น แต่ถ้ามีการจัดการกับเชลล์ stdout จะเห็นในแบบเรียลไทม์โดยไม่มีบัฟเฟอร์
พฤติกรรมนี้สามารถสังเกตได้ด้วยกระบวนการทับทิมเช่นเดียวกับกระบวนการย่อยที่ต้องรวบรวมผลลัพธ์แบบเรียลไทม์ เพียงสร้างสคริปต์ random.rb โดยมีบรรทัดต่อไปนี้:
5.times { |i| sleep( 3*rand ); puts "#{i}" }
จากนั้นสคริปต์ทับทิมเพื่อเรียกมันและส่งคืนผลลัพธ์:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
คุณจะเห็นว่าคุณไม่ได้รับผลลัพธ์แบบเรียลไทม์อย่างที่คุณคาดหวัง แต่ทั้งหมดในครั้งเดียวหลังจากนั้น STDOUT กำลังถูกบัฟเฟอร์แม้ว่าคุณจะเรียกใช้ random.rb ด้วยตัวเอง แต่ก็ไม่ได้บัฟเฟอร์ สิ่งนี้สามารถแก้ไขได้โดยการเพิ่มSTDOUT.flush
คำสั่งภายในบล็อกใน random.rb แต่ถ้าคุณไม่สามารถเปลี่ยนแหล่งที่มาได้คุณต้องหลีกเลี่ยงสิ่งนี้ คุณไม่สามารถล้างออกจากภายนอกกระบวนการได้
หากกระบวนการย่อยสามารถพิมพ์ไปยังเชลล์แบบเรียลไทม์ได้ก็ต้องมีวิธีจับสิ่งนี้ด้วย Ruby แบบเรียลไทม์เช่นกัน และมี. คุณต้องใช้โมดูล PTY ซึ่งรวมอยู่ในแกนทับทิมฉันเชื่อว่า (1.8.6 อย่างไรก็ตาม) สิ่งที่น่าเศร้าคือไม่มีเอกสาร แต่ฉันพบบางตัวอย่างของการใช้งานโชคดี
ครั้งแรกที่จะอธิบายสิ่ง PTY คือมันย่อมาจากขั้วหลอก โดยทั่วไปจะอนุญาตให้สคริปต์ Ruby นำเสนอตัวเองไปยังกระบวนการย่อยราวกับว่าเป็นผู้ใช้จริงที่เพิ่งพิมพ์คำสั่งลงในเชลล์ ดังนั้นพฤติกรรมที่เปลี่ยนแปลงใด ๆ ที่เกิดขึ้นเฉพาะเมื่อผู้ใช้เริ่มต้นกระบวนการผ่านเชลล์ (เช่น STDOUT ที่ไม่ถูกบัฟเฟอร์ในกรณีนี้) จะเกิดขึ้น การปกปิดข้อเท็จจริงที่ว่ากระบวนการอื่นได้เริ่มต้นกระบวนการนี้ทำให้คุณสามารถรวบรวม STDOUT แบบเรียลไทม์ได้เนื่องจากไม่ได้ถูกบัฟเฟอร์
เพื่อให้ทำงานกับสคริปต์ random.rb ในฐานะลูกให้ลองใช้รหัสต่อไปนี้:
require 'pty'
begin
PTY.spawn( "ruby random.rb" ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end