浅谈Lua的Coroutine-协程的多"线程"并发模型

看了一下《Programming in Lua》里的协程程序的运用,总觉得有点像雾里看花一样,捉不到重点,不知道怎么去运用,但在洗澡时灵光一闪,突然想明白了这不只是使用了Reactor(反应时同步时间分派)模式吗。在这里写篇博客跟大家分享一些拙见。

先贴一下之前看得不怎么懂的源码

function download (host, file)          -->协同程序

    local c = assert(socket.connect(host, 80))

    local count = 0 -- counts number of bytes read

    c:send("GET " .. file .. " HTTP/1.0\r\n\r\n")

    while true do

        local s, status = receive©

        count = count + string.len(s)

        if status == "closed" then break end

    end

    c:close()

    print(file, count)

end    



function receive (connection)        -->我把它叫做"中断程序"

    connection:timeout(0) --> do not block

    local s, status = connection:receive(2^10)

    if status == "timeout" then

        coroutine.yield(connection)

    end

    return s, status

end



threads = {}                               --> list of all live threads

function get (host, file)                --> 工厂函数

    local co = coroutine.create(function ()

    download(host, file)

    end)

    table.insert(threads, co)           --> insert it in the list

end



function dispatcher ()                   -->分派器函数    

    while true do

      local n = table.getn(threads)

      if n == 0 then break end  

      for i=1,n do

      local status, res = coroutine.resume(threads[i])

      if not res then    

        table.remove(threads, i)

        break

      end

    end

  end

end

首先来看一下

  dispatcher函数实际上充当了Reactor模式中的select和poll/epoll

  get这个工厂函数充当了向分派器注册“线程”(协同程序)的作用

  download与receive这两个函数在Reactor模式中共同起到一个线程的作用

  不同点是:1、以上Lua代码中通过额外的恢复/挂起操作代替了Reactor模式中的分派器检测系统资源来确定线程是否活动

       2、因为分派器与各“线程”(协同程序)的执行实际上都在一个线程中执行,不能利用系统在真正线程之间分时切换,必须手动实现切换。

  Coroutine-协程模型的优点是:

       1、切换上下文的代价比较小。

       2、不需要考虑同步问题。  

       

实际上按照Reactor模式使用多协程程序很简单

  只需要实现一个全局的分派器,开放注册“线程”的接口。写需要的协同程序(必须包含一个中断条件),并注册到分派器。

  运行分派器就可以实现简单的多线程并发。当然这只是一个最简单的模型,只能在当至少有一个“线程”有数据可读取的时候运行比较良好,如果各个“线程”都处于空闲状态,则分配器会不断轮询线程状态,导致消耗大量时间。

你可能感兴趣的:(coroutine)