Ruby中的任务/未来

什么是模式的惯用Ruby模拟,表示可能延迟的异步计算,可以订阅它的完成? 即.NET System.Threading.Task或Python 3.x concurrent.futures.future

请注意,这并不一定意味着multithreading – “未来”对象的实际实现可能会使用其他方式来调度工作和获取结果,并且超出了问题的范围。 该问题严格地涉及呈现给对象的用户的API。

我不确定vanilla Ruby,但EventMachine有延迟 。

另外,请查看这篇文章 。

 EM.run { detector = LanguageDetector.new("Sgwn i os yw google yn deall Cymraeg?") detector.callback { |lang| puts "The language was #{lang}" } detector.errback { |error| puts "Error: #{error}" } } 

纤维?

Fibers是在Ruby中实现轻量级协同并发的原语。 基本上它们是一种创建可以暂停和恢复的代码块的方法,就像线程一样。 主要区别在于它们永远不会被抢占,并且调度必须由程序员而不是VM完成。 链接

您可以使用像resque这样的作业队列
编写了一些纯ruby的快速示例

  1. 通过分叉子进程

     rd, wr = IO.pipe p1 = fork do rd.close # sleep is for demonstration purpose only sleep 10 # the forked child process also has a copy of the open file # handles, so we close the handles in both the parent and child # process wr.write "1" wr.close end wr.close puts "Process detaching | #{Time.now}" Process.detach(p1) puts "Woot! did not block | #{Time.now}" 1.upto(10) do begin result = rd.read_nonblock(1) rescue EOFError break rescue Exception # noop end puts "result: #{result.inspect}" system("ps -ho pid,state -p #{p1}") sleep 2 end rd.close __END__ ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0] Process detaching | 2012-02-28 17:05:49 +0530 Woot! did not block | 2012-02-28 17:05:49 +0530 result: nil PID STAT 5231 S+ result: nil PID STAT 5231 S+ result: nil PID STAT 5231 S+ result: nil PID STAT 5231 S+ result: nil PID STAT 5231 S+ result: "1" PID STAT 
  2. 通过在线程上进行回调

     require 'thread' Thread.abort_on_exception = true module Deferrable def defer(&block) # returns a thread Thread.new do # sleep is for demonstration purpose only sleep 10 val = block.call # this is one way to do it. but it pollutes the thread local hash # and you will have to poll the thread local value # can get this value by asking the thread instance Thread.current[:human_year] = val # notice that the block itself updates its state after completion end end end class Dog include Deferrable attr_accessor :age, :human_age attr_accessor :runner def initialize(age=nil) @age = age end def calculate_human_age_as_deferred! self.runner = defer do # can do stuff with the values here human_age = dog_age_to_human_age # and finally publish the final value after_defer { self.human_age = human_age } # return value of the block. used in setting the thread local human_age end end protected def dog_age_to_human_age (self.age / 7.0).round(2) end def after_defer(&block) block.call end end dog = Dog.new(8) dog.calculate_human_age_as_deferred! 1.upto(10) do sleep 2 puts "status: #{dog.runner.status} | human_age: #{dog.human_age.inspect}" break unless dog.runner.status end puts "== using thread local" dog = Dog.new(8) dog.calculate_human_age_as_deferred! 1.upto(10) do sleep 2 puts "status: #{dog.runner.status} | human_age: #{dog.runner[:human_year].inspect}" break unless dog.runner.status end __END__ ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0] status: sleep | human_age: nil status: sleep | human_age: nil status: sleep | human_age: nil status: sleep | human_age: nil status: false | human_age: 1.14 == using thread local status: sleep | human_age: nil status: sleep | human_age: nil status: sleep | human_age: nil status: sleep | human_age: nil status: false | human_age: 1.14 

线程比分叉子进程消耗更少的内存,但分叉是健壮的。 线程中未处理的错误可能会导致整个系统崩溃。 而在子进程中出现未处理的错误,只会导致子进程失效

其他人指出纤维和事件机器(使用EM :: Deferrable和EM.defer)是另一种选择

纤维和线程需要仔细编码。 代码可能以微妙的方式出错。
光纤也使用先发制人的多任务处理,因此代码库必须表现良好

Eventmachine很快但它是一个独特的世界(就像在python中扭曲)。 它有自己独立的IO堆栈,因此必须编写所有库以支持eventmachine。 话虽如此,我认为图书馆支持不是eventmachine的问题

lazy.rb提供“期货”,但它们似乎与您描述的完全不同(或者我预期):

此外,库提供期货,其中计算立即在后台线程中运行。

因此,您无法在以后计算它们,或者通过其他方式将值插入它们(可能来自网络)。

也许我错过了一些东西,但如果你在对deepak的回复中描述的情况如此,那么为什么不将C API包装为Ruby扩展并提供一个Ruby方法来接受与你需要的回调相对应的块? 这也是非常惯用的Ruby。

下面是一个示例章节,介绍如何使用为Ruby 1.9更新的“Pickaxe”书籍扩展Ruby with C: http : //media.pragprog.com/titles/ruby3/ext_ruby.pdf 。

更新:这里有一些链接处理Ruby中的Rubyexception以及它的C接口。

我发现这非常有帮助:

https://github.com/wireframe/backgrounded

它是一个gem,只允许将方法推送到后台任务。

线程gem可能是有趣的。 您可以创建一个在后台处理内容的线程池。 gem还支持许多其他function,如未来,延迟等。看看github回购 。

它似乎适用于各种ruby版本,而不仅仅是1.9+,这就是我使用它的原因。