【问题标题】:how to wrap all class methods in a class in timeout wrappers如何在超时包装器中将所有类方法包装在一个类中
【发布时间】:2014-04-23 14:30:17
【问题描述】:

我正在尝试创建一个类方法,它将在其他类方法周围放置一个超时包装器。

class FooBar

  def self.slow_add(a,b,c)
    sleep 1
    a + b + c
  end

  LIST = [:slow_add]

  class << self
    LIST.each do |x|
      alias_method "#{x}_without_timeout", "#{x}"
      define_method("#{x}_with_timeout") do |*args|
        timeout(4){self.send(x, *args)}
      end
      alias_method "#{x}", "#{x}_with_timeout"
    end
  end
end

但是,生成的超时方法总是超时,即使它们不应该:

2.0.0p353 :152 >   FooBar.slow_add_without_timeout(1, 2, 3)
 => 6 
2.0.0p353 :153 > FooBar.slow_add_with_timeout(1, 2, 3)
Timeout::Error: execution expired
...
...
2.0.0p353 :156 >   FooBar.slow_add(1, 2, 3)
Timeout::Error: execution expired
...
...

感谢您的帮助。

【问题讨论】:

    标签: ruby methods timeout metaprogramming alias


    【解决方案1】:

    如果您能够向您的类发送超时消息很重要,我建议创建一个辅助类,它将每个方法调用包装在超时块中并将消息转发到原始引用对象。像这样的:

    require 'timeout'
    
    class TimeoutHandler
      attr_reader :seconds, :object
      def initialize(object, seconds)
        @seconds = seconds
        @object = object
      end
    
      def method_missing(name, *args, &block)
        Timeout::timeout(seconds){ object.send(name, *args, &block) }
      end
    end
    

    您可以像这样创建TimeoutHandler 的实例:

    class FooBar
      class << self
        def timeout(seconds = 4)
          TimeoutHandler.new(self, seconds)
        end
      end
    end
    

    因此,当您需要使用超时块中断消息时,您只需先调用timeout

    FooBar.timeout.slow_add(1, 2, 3)
    

    您可以在 mixin 中编写 timeout 方法,以包含在您需要此功能的类中。

    然而,这一切对我来说似乎很做作,我需要一个很好的理由来实现它,而不是仅仅使用更简单的 Timeout::timeout { FooBar.slow_add(1, 2, 3) },它不需要任何额外的实现。

    【讨论】:

    • 这听起来是个不错的解决方案。你能告诉我为什么我的原始解决方案有效地导致堆栈溢出吗?(删除对 sleep 方法的调用使得在 irb 中调用方法时更明显)。我必须缺少关于 alias_method 的一些东西。
    • 您正在通过别名回x 来设置递归。对x 的调用将无限期地发送回x
    猜你喜欢
    • 2021-05-01
    • 1970-01-01
    • 2021-10-24
    • 2021-09-25
    • 2016-12-29
    • 2019-01-09
    • 1970-01-01
    • 2019-11-01
    • 2017-05-04
    相关资源
    最近更新 更多