首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Ruby的popen3会因为“打开太多文件”而崩溃呢?

为什么Ruby的popen3会因为“打开太多文件”而崩溃呢?
EN

Stack Overflow用户
提问于 2013-10-14 21:22:26
回答 1查看 541关注 0票数 1

我使用Popen3运行一些Perl脚本,然后将它们的输出转储到文本文件中。在文本文件中,我搜索Perl脚本的结果。在运行大约40分钟(约220份文件)后,我得到了错误。

代码语言:javascript
复制
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

剧本在下面。

代码语言:javascript
复制
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的太多文件,还是我没有正确地使用它。

谢谢你帮我!

经过一些非常有用的提示之后,我重新分析了我的脚本!代码运行得很好!

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-15 00:34:11

考虑到这一点:

代码语言:javascript
复制
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中的OptionParser类。
  • Ruby允许我们将一个块传递给File.open,当块退出时,它会自动关闭文件。这是Ruby的一个主要优点,并有助于减少您所看到的错误。Logger不会这样做,所以必须格外小心,以避免像您正在做的那样,留下挂着的文件句柄。相反,请使用: log = Logger.new($testFile) log.info(line) log.close 立即关闭手柄。你是在循环之外做的,而不是在里面,所以你有一堆打开的句柄。 还要考虑是否需要Logger,或者普通的File.open是否就足够了。记录器还有额外的开销。
  • 您对$testFile的使用是有问题的。$variables是全局的,它们的使用通常是指你做错了什么,至少直到你理解了为什么和什么时候应该使用它们。我会用它重构代码。
  • 在Ruby中,变量和方法在snake_case中,而不是用于类和模块的CamelCase中。这似乎不太像until_you_run_into CodeDoingTheWrongThing and_have_to_read_it。(注意到你的大脑是如何破译骆驼箱的吗?)

一般来说,我怀疑这是否是最快的方式去做你想做的事。我怀疑您可以使用greptail编写一个shell脚本,该脚本至少可以跟上进度,并可能运行得更快。你可以坐下来和你的系统管理员一起做些脑筋检查。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19369535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档