ruby 每秒执行x次

bvuwiixz  于 2023-01-30  发布在  Ruby
关注(0)|答案(3)|浏览(121)

我在一个技术测试中遇到了一个有趣的ruby问题。在给定的时间内我没有找到答案,但我认为它很有趣,希望其他人能回答这个问题。你会如何编写代码来做:
2 ×每秒{ p '工作' }
我试着用per_second方法扩展枚举器类。per_second方法只是休眠正确的毫秒数。但是我被困在试图以优雅的方式将“2”参数传递给per_second方法。也许使用从2.x返回的枚举器的长度?

mbzjlibv

mbzjlibv1#

利用现代Ruby的魔力,我们可以编写refinementInteger,以扩展times方法,但只能在选择这种细化行为的作用域中。

module IntegerExt

  # Define a refinement of the Integer type. This is like
  # monkeypatching but is local to modules or files that opt in to the
  # change.
  refine Integer do
    # Re-write the times function.
    def times(&block)
      if block
        # If a block was provided, then do the "normal" thing.
        super(&block)
      else
        # Otherwise, get an enumerator and augment its singleton class
        # with PerSecondEnumerator.
        super().extend PerSecondEnumerator
      end
    end
  end

  # This module provides the per_second method on enumerators that
  # need it.
  module PerSecondEnumerator
    def per_second(&block)
      loop do
        sleep(1.0/self.size)
        block.call
      end
    end
  end

end

# If a module wishes to have this functionality, it needs to opt in
# with this 'using' statement. The per_second syntax only works on
# objects constructed within the lexical scope of this refinement.
using IntegerExt

puts 2.times.inspect # Still works
2.times.per_second { p 'works' }

这就解决了Aria回答中的几个问题。我们不再对内置类进行全局monkey-patching。我们只在任何模块的词法作用域中修改类,只要该模块 * 希望 * 看到我们的修改。此外,由于我们改进了times,而不是直接改进Enumerator,因此我们的per_second只适用于通过times构造的枚举器。所以不可能做像[1, 2, 3, 4, 5].per_second { ... }这样无意义的事情。

8iwquhpp

8iwquhpp2#

你可以这样做:

Enumerator.define_method(:per_second) do |&block|
  loop do
    sleep(1.0/self.size)
    block.call
  end
end

3.times.per_second { puts "works" }

但这里有一些警告:
1.不建议扩展Ruby基类,如Enumerator、Integer等。
1.就像有人在你的帖子的评论中说的那样,使用size并不好,因为你可以使用字符串或数组来代替整数。

igetnqfo

igetnqfo3#

下面是使用简单对象的另一个选项

obj = Object.new 

def obj.each_second(times: 1, duration: Float::INFINITY)
  return to_enum(__method__, times: times, duration: duration) unless block_given?
  i = 0
  until i >= duration * times do
    i += 1 
    yield(i)
    sleep(1.0/times)
  end
end 

enum = obj.each_second(times: 5, duration: 3)

enum.each { |n|  puts "#{n} Works"}
# 1 Works
# 2 Works
# 3 Works
# 4 Works
# 5 Works
# 6 Works
# 7 Works
# 8 Works
# 9 Works
# 10 Works
# 11 Works
# 12 Works
# 13 Works
# 14 Works
# 15 Works
#=> nil

您可以指定每秒执行块的次数和执行的持续时间(以秒为单位)。(默认为无限期每秒1次迭代)

注意:这并不考虑块本身的实际阻塞执行时间,因此每秒迭代次数无法保证,可能会小于指定的次数。

相关问题