一、 概念
协同程序提供一种协作式的多线程。每个协同程序都等于是一个线程。一对yield-resume可以将执行权在不同线程之间切换。然而,协同程序与常规的多线程的不同之处在于,协同程序是非抢先式的。就是说,当一个协同程序在运行时,是无法从外部停止它的。只有当协同程序显示地要求挂起时(调用yield),它才会停止。对于有些应用而言,这没有问题,而对于另外一些应用则可能无法接受这种情况。当不存在抢先时,编程会简单许多。无需为同步的bug而抓狂,在程序中所有线程间的同步都是显式的,只需确保一个协同程序在它的临界区域之外调用yield即可。对于这样非抢先式的多线程来说,只要有一个线程调用了一个阻塞操作,整个程序在该操作完成前,都会停止下来。对于大多数应用程序来说,这种行为是无法接受的,这也就导致了许多程序员放弃协同程序,转而使用传统的多线程
下面用一个有趣的方法来解决这个问题:
通过HTTP下载几个远程文件。(该例子中会使用Lua的socket库)
为了下载一个文件,必须先打开一个到该站点的连接,然后发送下载文件的请求并且接收文件,最后关闭连接
1、 require “socket”--加载LuaSocket库
2、local host = "www.w3.org" --定义主机
local file1 = "/TR/REC-html132.html --下载的文件
3、c = assert(socket.connect(host,80))--连接到该站点的80端口(打开一个TCP连接,连接到该站点的80端口)
4、c:send("GET " .. file1 .. " HTTP/1.0\r\n\r\n) --(连接完成后将返回一个连接对象,可以用这个连接对象来发送文件请求)
5、while true do
local s,status,partial=c:receive(2^10)
io.write(s or partial)
if status=="closed" then
break
end
end
--在正常情况下receive函数会返回一个字符串。若发生错误,则会返回nil,并且附加错误代码(status)及出错前读取到的内容partial。当主机关闭连接时,就将其余接收到的内容打印出来,然后退出接收循环。
6、c:close() -- 关闭连接
二、接下来下载几个文件,最笨的办法就是逐个下载,但是太慢。程序大部分时间花费在等待数据的接收上。更明确地说,是将时间花在了receive阻塞调用上。因此如果一个程序可以同时下载所有文件的话,其效率就会快很多了。
当一个连接没有可用数据时,程序便可以从其他的连接处读取数据。
很明显协同程序提供了一种简便的方式来构建这种并发下载。
为每个下载任务创建一个新的线程,只要一个线程无可用数据,它就把控制权转让给一个简单的调度程序。
而这个调度程序则会调用其他下载线程。
在以协同程序来重写程序,先将前面的下载代码重新写:
function receive(connection)
local s,status,partial = connection:receive(2^10)
return s or partial,status
end
function download(host,file)
local c = assert(socket.connect(


8181

被折叠的 条评论
为什么被折叠?



