`

Ruby Coroutine

    博客分类:
  • Ruby
阅读更多
Ruby1.9提供了Fiber,提供了Coroutine的功能。
    Fibers作为实现轻量级合作并发的基础设施,和线程很像,提供了创建一个可以pause和resume的代码块,
但Fibers是非抢占式的,必须由程序而不是VM来调度。每一个fiber提供了4kB的栈空间可以允许fiber的
block进行深层嵌套函数调用。这是rdoc对Fiber的描述。

    Ruby的Fiber就是传说中Coroutine的实现,在lua中,coroutine被广泛使用。Ruby中coroutine的
强大功能,势必会被发扬光大。Ruby中的Fiber和lua中的coroutine基本类似,都是asymmetric coroutine,
都提供了new/create,resume和yield的操作。
看个rdoc的例子:
  fiber = Fiber.new do
    Fiber.yield 1
    2
  end

  puts fiber.resume #=>1
  puts fiber.resume #=>2
  puts fiber.resume #=>FiberError: dead fiber called

Fiber有三种状态:suspend、running、dead。Fiber被new之后处于suspend状态,当调用resume时开始运行(running),coruntine执行的block完毕或者出错时dead.
上面的例子,我们new一个fiber,这时fiber处于suspend,当我们调用resume的时候,开始执行,Fiber.yield
放弃当前的执行控制,将控制权交给resume的调用者。第二次调用fiber.resume时从Fiber.yeild 1返回,开始执行下一句代码,这时这个fiber执行完毕,所以第三次调用时fiber已经dead。

resume参数可以是任何个,第一次调用的时候作为block的参数,后面的调用作为yield的返回值。

fiber = Fiber.new do |first|
    second = Fiber.yield first + 2
end

puts fiber.resume 10 #12
puts fiber.resume 14 #14
puts fiber.resume 18 #FiberError: dead fiber called



通过上面我们已经熟悉了Coroutine,下面我们创建一个fib数列生成器的coroutine,小小练习一下:

fib = Fiber.new do  
   x, y = 0, 1 
   loop do  
    Fiber.yield y 
    x,y = y,x+y 
   end 
end 
20.times { puts fib.resume }


coroutinue最常用的场合就是合作并发的程序,producer和consumer是最典型的方式:
一个偶数生产者和消费者:
def even_producer #even number producer
    Fiber.new do
        value = 0
        loop do
            Fiber.yield value
            value += 2
        end
    end
end

def consumer(source)
    Fiber.new do
        10.times do
            next_val = source.resume
            puts next_val
        end
    end
end

consumer(even_producer).resume

在加点东东,加个过滤器,我只想要是3的倍数的偶数:
def multiple_of_three_filter(source)
    Fiber.new do
        loop do
            next_val = source.resume
            Fiber.yield next_val if next_val % 3 == 0
        end
    end
end
consumer(multiple_of_three_filter(even_producer)).resume

我们看到可以像Unix的管道一样将多个coroutine连结起来,我们甚至可以定义像Unix shell一样的
管道操作符Pipelines Using Fibers in Ruby 1.9
even_producer | multiple_of_three_filter | consumer
class PipelineElement
    attr_accessor :source

    def initialize
        @fiber_delegate = Fiber.new do
            process
        end
    end

    def |(other)
        other.source = self
        other
    end

    def resume
        @fiber_delegate.resume
    end

    def process
        while value = input
            handle_value(value)
        end
    end

    def handle_value(value)
        output(value)
    end

    def input
        source.resume
    end

    def output(value)
        Fiber.yield(value)
    end
end

class EvenProducer < PipelineElement
    def process
        value = 0
        loop do
            output(value)
            value += 2
        end
    end
end

class MultipleOf < PipelineElement
    def initialize(factor)
        @factor = factor
        super()
    end

    def handle_value(value)
        output(value) if value % @factor == 0
    end
end

even_producer = EvenProducer.new
multiples_of_three_filter = MultipleOf.new(3)
multiples_of_seven_filter = MultipleOf.new(7)
pipeline = even_producer | multiples_of_three_filter | multiples_of_seven_filter

10.times do 
    puts pipeline.resume
end


使用shell的管道每次需要创建一个进程,而使用coroutine每次只需要创建一个轻量级的Fiber

关于asymmetric coroutine和symmetric coroutine
1)asymmetric coroutine:提供了两种控制转换操作:(re)invoking和suspending一个coroutine,suspending将控制流程返回给coroutine的调用者。这个过程和调用和被调用的routine类似(routine在现代语言中被实现为函数、方法、过程,又叫subroutine),所以这种方式非常容易被使用传统编程语言的程序员接受,这也是大多数语言实现asymmetric coroutine的原因之一,其他的原因:比如lua是和c/c++结合比较紧密的语言,如果实现symmetric coroutine则要求c/c++支持coroutine,这显然是不现实的,另外symmetric的也很容易用asymmetric描述。
2)symmetric coroutine:只提供了一种控制上述操作的操作。
分享到:
评论
1 楼 boreas_baosj 2011-04-02  
为什么我每次搜索WSRM1124: No sequence registered with id,都搜到你这篇文章,而且google的快照下面也有显示这个关键字。但是貌似此帖并不是说这个问题的。
LZ是不是写过类似的帖子呢,如果有解决这个错误的方法,请赐教。
错误:com.sun.xml.ws.rx.rm.runtime.sequence.UnknownSequenceException: WSRM1124: No sequence registered with id [ urn:uuid:414e525a-3b88-41b0-8145-cb33abac137a ] 
帖子:http://www.iteye.com/problems/61911
在java.net上看到这样的方式试了也是不行
http://forums.java.net/node/686822

相关推荐

    用Python,Lua和Ruby语言设计游戏-Game.Programming.with.Python.Lua.And.Ruby.

    Lua的Coroutine机制也允许实现轻量级的并发,对于实现复杂的多任务系统非常有用。 Ruby虽然在游戏开发中不如Python和Lua常见,但其动态特性和元编程能力使其在某些场景下独具优势。例如,Ruby的Rubygame库可以用于...

    线程与并发:Ruby并行世界的探索之旅

    - **协程 (Coroutine)**:一种可暂停和恢复执行的程序组件。 Ruby 支持多种并发模型,包括多线程、多进程及使用协程库(如 Goliath 或 Reel)。下面是一个使用进程进行并发处理的示例代码: ```ruby require '...

    la-coroutine.github.io:La Coroutine网站(第三名,法国里尔)

    La Coroutine网站 安装 首先,安装Ruby。 然后,安装Bundler和所有必需的插件: $ gem install bundler $ bundle install 用法 运行服务器: $ jekyll serve 打开浏览器,然后转到 执照 本网站是根据知识共享署名...

    leetcode中国-myleft:御舟家园

    Coroutine C MPI C monitoring C Secure && 安全 C Web C Websocket Websocket && Tools D Blender Ruby 安全扫描 NoSQL 中文分词 GNOME DOC Language && programming language IM && XMPP && SIP libuv 流程图 Java...

    android应用源码精带服务端网络办公完整源码.zip

    6. **异步处理**:Android应用通常使用AsyncTask、IntentService或现代的Coroutine进行后台任务处理,避免阻塞主线程,保证界面的流畅性。 7. **权限管理**:考虑到Android系统的权限模型,源码中可能存在对运行时...

    Web并发模型粗浅探讨

    5. 协程(coroutine):一种用户态轻量级线程,它允许用户在单个线程内进行挂起和恢复操作,适合I/O密集型应用。 在实际应用中,选择哪种并发模型取决于应用场景、性能需求和开发资源。例如,I/O密集型应用适合采用...

    ngx_lua内幕

    Lua支持可中断/重入的虚拟机(VM)和原生的协程(coroutine),这为实现异步非阻塞I/O提供了便利,无需关心现场保护问题,切换开销也小。因此,Lua非常适合用于I/O密集型应用,可以有效地避免I/O操作阻塞等待造成的...

    Unity面试题加强版

    #### 一、Unity3D中的协程(coroutine)与C#线程的区别 1. **并发性**: - 多线程:能够同时运行多个线程,实现真正的并行计算。 - 协程:在任何指定时刻只能运行一个协程。正在运行的协程只有在必要的时候才会被...

    Unity编辑器:基于NGUI的引用检测工具

    在处理NGUI的引用检测时,要注意一些常见的问题,比如事件监听器没有正确移除、静态变量保留了对对象的引用,或者Unity的Coroutine可能导致对象无法被垃圾回收。解决这些问题需要对Unity的生命周期和内存管理有深入...

Global site tag (gtag.js) - Google Analytics