我正在使用Popen3运行一些Perl scrips,然后将其输出转储到文本文件中。进入文本文件后,我会搜索Perl脚本的结果。运行约40分钟后,我收到错误,大约是220个文件。
ruby/1.8/open3.rb:49:in `pipe': Too many open files (Errno::EMFILE)
from /ruby/1.8/open3.rb:49:in `popen3'
from ./RunAtfs.rb:9
from ./RunAtfs.rb:8:in `glob'
from ./RunAtfs.rb:8
脚本如下。
require 'logger'
require 'open3'
atfFolder = ARGV[0]
testResult = ARGV[1]
res = "result.txt"
open('result.txt', 'w') { }
Dir.glob(atfFolder+'/*.pl') do |atfTest|
Open3.popen3("atf.pl -c run-config.pl -t #{atfTest}") do |i, o, e, t|
while line = e.gets
$testFile = testResult + line[/^[0-9]+$/].to_s + "testOutput.txt"
log = Logger.new($testFile)
log.info(line)
end
log.close
end
lastLine = `tail +1 #{$testFile}`
file = File.open(res, 'a')
if(lastLine.include? "(PASSED)")
file.puts("Test #{atfTest} --> Passed")
file.close
File.delete($testFile)
else
file.puts("Test #{atfTest} --> Failed!")
file.close
end
end
此脚本正在处理4900个Perl文件,所以我不知道这是popen3
的文件太多,还是我没有正确使用它。
感谢您的帮助!
我在一些非常有用的指针后重构了我的脚本!代码工作得很好!
require 'open3'
atf_folder, test_result = ARGV[0, 2]
File.open('result.txt', 'w') do |file| end
Dir.glob("#{ atf_folder }/*.pl") do |atf_test|
test_file = atf_test[/\/\w+.\./][1..-2].to_s + ".txt"
comp_test_path = test_result + test_file
File.open(comp_test_path, 'w') do |file| end
Open3.popen3("atf.pl -c run-config.pl -t #{ atf_test }") do |i, o, e, t|
while line = e.gets
File.open(comp_test_path, 'a') do |file|
file.puts(line)
end
end
end
last_line = `tail +1 #{comp_test_path}`
File.open('result.txt', 'a') do |file|
output_str = if (last_line.include? "(PASSED)")
File.delete(comp_test_path)
"Passed"
else
"Failed!"
end
file.puts "Test #{ atf_test } --> #{ output_str }"
end
end
答案 0 :(得分:1)
考虑一下:
require 'logger'
require 'open3'
atf_folder, test_result = ARGV[0, 2]
Dir.glob("#{ atf_folder }/*.pl") do |atf_test|
Open3.popen3("atf.pl -c run-config.pl -t #{ atf_test }") do |i, o, e, t|
while line = e.gets
$testFile = test_result + line[/^[0-9]+$/].to_s + "testOutput.txt"
log = Logger.new($testFile)
log.info(line)
log.close
end
end
lastLine = `tail +1 #{ $testFile }`
File.open('result.txt', 'a') do |file|
output_str = if (lastLine.include? "(PASSED)")
File.delete($testFile)
"Passed"
else
"Failed!"
end
file.puts "Test #{ atf_test } --> #{ output_str }"
end
end
当然,它没有经过测试,因为没有样本数据,但是它的编写更为个性化。
注意事项:
atf_folder, test_result = ARGV[0, 2]
切片ARGV数组,并使用并行分配一次检索两个参数。您应该测试以确定您获得了它们的值。而且,当您转向更复杂的脚本时,请利用Ruby的STDLIB中的OptionParser类。 Ruby允许我们将一个块传递给File.open
,它会在块退出时自动关闭文件。这是Ruby的主要优势,有助于减少您所看到的错误。 Logger
不会这样做,所以必须特别小心,以避免像你一样留下挂起的文件句柄。相反,使用:
log = Logger.new($testFile)
log.info(line)
log.close
立即关闭手柄。你是在循环之外,而不是在循环中,所以你有一堆打开的句柄。
还要考虑是否需要Logger,或者常规File.open
是否足够。记录器还有额外的开销。
$testFile
的使用值得怀疑。 $variables
是全局变量,它们的使用通常表明你做错了什么,至少在你理解为什么以及何时应该使用它们之前。我会使用它来重构代码。总的来说,我怀疑这是否是做你想做的最快的方法。我怀疑你可以使用grep
或tail
来编写一个shell脚本,它至少可以跟上,并且可能运行得更快。你可能会坐下来使用你的系统管理员并做一些脑力训练。