1

我正在使用 Popen3 运行一些 Perl 脚本,然后将它们的输出转储到文本文件中。在文本文件中,我搜索 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
4

1 回答 1

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

当然,它未经测试,因为没有示例数据,但它更符合 Ruby 的习惯性编写。

注意事项:

  • 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是全局变量,它们的使用通常表明你做错了什么,至少在你理解为什么以及何时应该使用它们之前。我会用它重构代码。
  • 在 Ruby 中,变量和方法是在snake_case 中,而不是在用于类和模块的 CamelCase 中。直到_you_run_into CodeDoingTheWrongThing 和_have_to_read_it 这似乎并不多。(注意你的大脑是如何陷入破译骆驼案的?)

一般来说,我质疑这是否是做你想做的最快的方法。我怀疑你可以编写一个 shell 脚本,grep或者tail至少可以跟上,并且可能运行得更快。你可能会和你的系统管理员坐下来做一些脑力劳动。

于 2013-10-15T00:34:11.203 回答