2013-06-21 7 views
12

यह कोड में समझाने के लिए सबसे आसान है:एक पॉपन काम के भीतर टाइमआउट, लेकिन एक टाइमआउट के अंदर पॉपन नहीं करता है?

require 'timeout' 

puts "this block will properly kill the sleep after a second" 

IO.popen("sleep 60") do |io| 
    begin 
    Timeout.timeout(1) do 
     while (line=io.gets) do 
     output += line 
     end 
    end 
    rescue Timeout::Error => ex 
    Process.kill 9, io.pid 
    puts "timed out: this block worked correctly" 
    end 
end 

puts "but this one blocks for >1 minute" 

begin 
    pid = 0 
    Timeout.timeout(1) do 
    IO.popen("sleep 60") do |io| 
     pid = io.pid 
     while (line=io.gets) do 
     output += line 
     end 
    end 
    end 
rescue Timeout::Error => ex 
    puts "timed out: the exception gets thrown, but much too late" 
end 

मेरे दो ब्लॉकों के मानसिक मॉडल समान होता है:

flow chart

तो, मुझे याद आ रही?

संपादित करें: ट्विटर पर सुझाव दिया गया है कि पहले मामले में, किसी कारण से, पाइप सॉकेट गैर-अवरोधन मोड में जाती है, लेकिन दूसरे में यह नहीं होती है। मैं किसी भी कारण से नहीं सोच सकता कि ऐसा क्यों होगा, और न ही मैं यह समझ सकता हूं कि वर्णनकर्ता के झंडे कैसे प्राप्त करें, लेकिन कम से कम एक व्यावहारिक उत्तर है? उस संभावना पर काम करना।

+0

आप कौन सी रूबी चल रहे हैं? –

+0

यह व्यवहार कम से कम 1.8.7 और 1.9.3 पर होता है। दोनों ब्लॉक पर सभी 60 के लिए jruby ब्लॉक, जो व्यवहार है मैं एक prei अनुमान लगाया होगा। – llimllib

+0

ध्यान दें कि आपके 'मेरे लिए दो ब्लॉक के बीच "रखता है (" लेकिन यह एक ... ")' पहली 'नींद' पूरा होने तक इंतजार कर रहा है, क्योंकि पहले आईओ # पॉपन ब्लॉक कॉल में 'प्रतीक्षापिप() के लिए कर्तव्यपूर्वक है '। यदि आप यह नहीं चाहते हैं, तो आपके बचाव तर्क को बाल प्रक्रिया को मारने की जरूरत है। – pilcrow

उत्तर

13

अहा, सूक्ष्म देखें।

दूसरे मामले में आईओ # पॉपन ब्लॉक के अंत में एक छिपी हुई, ensure खंड अवरुद्ध है। टाइमआउट :: त्रुटि समय पर उठाया गया है, लेकिन आप rescue नहीं कर सकते हैं जब तक कि निष्पादन उस अंतर्निहित ensure खंड से निष्पादन न हो जाए।

Under the hood, IO.popen(cmd) { |io| ... } कुछ इस तरह है:

def my_illustrative_io_popen(cmd, &block) 
    begin 
    pio = IO.popen(cmd) 
    block.call(pio)  # This *is* interrupted... 
    ensure 
    pio.close   # ...but then control goes here, which blocks on cmd's termination 
    end 

और आईओ # पास कॉल वास्तव में है और अधिक या कम एक pclose(3), जो सो बच्चे बाहर निकलता है जब तक waitpid(2) में आप ब्लॉक कर रहा है।

तुम इतनी तरह इस की पुष्टि कर सकते हैं:

#!/usr/bin/env ruby 

require 'timeout' 

BEGIN { $BASETIME = Time.now.to_i } 

def xputs(msg) 
    puts "%4.2f: %s" % [(Time.now.to_f - $BASETIME), msg] 
end 

begin 
    Timeout.timeout(3) do 
    begin 
     xputs "popen(sleep 10)" 
     pio = IO.popen("sleep 10") 
     sleep 100      # or loop over pio.gets or whatever 
    ensure 
     xputs "Entering ensure block" 
     #Process.kill 9, pio.pid  # <--- This would solve your problem! 
     pio.close 
     xputs "Leaving ensure block" 
    end 
    end 
rescue Timeout::Error => ex 
    xputs "rescuing: #{ex}" 
end 

तो, आप क्या कर सकते हैं?

आपको इसे स्पष्ट तरीके से करना होगा, क्योंकि दुभाषिया आईओ # पॉपन ensure तर्क को ओवरराइड करने का कोई तरीका नहीं दिखाता है। आप उपरोक्त कोड को प्रारंभिक टेम्पलेट के रूप में उपयोग कर सकते हैं और उदाहरण के लिए kill() लाइन को असम्बद्ध कर सकते हैं।

+0

मैं io.c पर इतने लंबे समय तक देख रहा था, सुनिश्चित करने के बिना बस कुछ ही पंक्तियों * ऊपर * सुनिश्चित कर रहा हूं, इसे सुनिश्चित किए बिना या बिल्कुल विचार कर रहा हूं। महान जवाब, बहुत बहुत धन्यवाद। – llimllib

+0

क्या इस समाधान के साथ बाहर निकलने की स्थिति प्राप्त करना संभव है? – tiktak

0

पहले ब्लॉक में, टाइमआउट बच्चे में उठाया जाता है, इसे मारता है और माता-पिता को नियंत्रण वापस कर देता है। दूसरे ब्लॉक में, माता-पिता में टाइमआउट उठाया जाता है। बच्चे को संकेत कभी नहीं मिलता है।

io.chttps://github.com/ruby/ruby/blob/trunk/io.c#L6021 और timeout.rbhttps://github.com/ruby/ruby/blob/trunk/lib/timeout.rb#L51

+0

मुझे पता है कि यह एक विस्तृत उत्तर बिल नहीं है, लेकिन इस तरह मैंने ब्लॉक को पढ़ा है। –

+1

आईओ # पॉपन को पारित एक ब्लॉक मूल प्रक्रिया के संदर्भ में निष्पादित किया जाता है। मुझे यकीन नहीं है कि आपका मतलब क्या है जब आप कहते हैं कि बाल प्रक्रिया "संकेत प्राप्त कर सकती है या नहीं"। – pilcrow

+0

@ जोनाथनजुलियन मैंने उन दो फाइलों को एक स्प्लिट स्क्रीन में खोल दिया है, इसे समझने की कोशिश कर रहा है। जहां तक ​​मैं कह सकता हूं, टाइमआउट को दोनों उदाहरणों में मुख्य धागे से उत्पन्न किया गया है। यहां वह जगह है जहां पॉपन इसे पारित करता है: https://github.com/ruby/ruby/blob/trunk/io.c#L6075 – llimllib

संबंधित मुद्दे