lua程序设计第二版 读书笔记(9-10章)

来源:互联网 发布:nginx ssl 泛域名 编辑:程序博客网 时间:2024/05/17 07:17
 


书本下载地址                       http://download.csdn.net/detail/myy2012/5349646

本部分下载地址                   http://download.csdn.net/detail/myy2012/5353143         

 

lua程序设计第二版 读书笔记(1-4章)
第一章 开始
第二章 类型与值
第三章 表达式
第四章 语句
http://blog.csdn.net/myy2012/article/details/8900424

lua程序设计第二版 读书笔记(5-8章)
第五章 函数
第六章 深入函数
第七章 迭代器与泛型for
第八章 编译执行与错误
http://blog.csdn.net/myy2012/article/details/8906466

lua程序设计第二版 读书笔记(9-10章)
第九章 协同程序
第十章 完整的实例
http://blog.csdn.net/myy2012/article/details/8911206

lua程序设计第二版 读书笔记(11-14章)
第十一章 数据结构
第十二章 数据文件与持久性
第十三章 元表metatable与元方法meatmethod
第十四章 环境
http://blog.csdn.net/myy2012/article/details/8914457

lua程序设计第二版 读书笔记(15-17章)
第十五章 模块与包
第十六章  面向对象编程
第十七章 弱引用 table
http://blog.csdn.net/myy2012/article/details/8921632

lua程序设计第二版 读书笔记(18-21章)
第十八章 数学库
第十九章 table库
第二十章 字符串库
第二十一章 IO库
http://blog.csdn.net/myy2012/article/details/8925895

lua程序设计第二版 读书笔记(22-23章)
第二十二章 操作系统库
第二十三章 调试库
http://blog.csdn.net/myy2012/article/details/8930181

 

 

第九章 协同程序(coroutine

协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其他协同程序共享全局变量和其他大部分东西。

一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并正在运行的协同程序只会在其显式地要求挂起(suspend)时,它的执行才会暂停。

9.1协同程序基础

Lua将所有有关于协同程序的函数放置在一个名为“coroutine”的table中。函数create用于创建新的协同程序,它只有一个参数(一个函数)。该函数的代码就是协同程序所需执行的内容。Create会返回一个thread类型的值,用以表示新的协同程序。例如:

co=coroutine.create(function() print("hi") end)print(co) --thread: 005EB9B8

 

一个协同程序可以处于4种不同的状态:挂起(suspended)、运行(running)、死亡(dead)和正常(normal)。当创建一个协同程序时,它处于挂起状态(协同程序不会在创建它时自动执行其内容)。可以通过函数status来检查协同程序的状态:

print( coroutine.status( co ))  -- suspended

 

coroutine.resume用于启动或者再次启动一个协同程序的执行,并将状态从挂起改为运行。

coroutine.resume(co)-- hi

正常状态:当一个协同程序A唤醒另一个协同程序B时,A就处于一个特殊状态(正常状态normal),既不是挂起状态(无法继续A的执行),也不是运行状态(B在运行)。

Lua的协同程序可以通过一对resume-yield来交换数据。

A. 在第一次调用resume时,并没有对应的yield在等待它,因此所有传递给resume的额外参数都将视为协同程序主函数的参数。例如:

co3=coroutine.create(function(a, b, c)  print("co3", a, b, c)  end)coroutine.resume(co3, 1, 2)--co3 1 2  nil

B. 在resume调用返回的内容中,第一个值为true 表示没有错误,而后面所有的值都是对应yield传入的参数。例如:

co4=coroutine.create(function(a, b)coroutine.yield(a+b, a-b)end)print("co4", coroutine.resume(co4, 25, 10)) --co4  true  35  15

 

C. yield返回的额外值就是对应resume传入的参数。例如:

co5=coroutine.create(function()print("co5", coroutine.yield())end)coroutine.resume(co5)coroutine.resume(co5, 4, 5)--co5 4 5
 

D. 当一个协同程序结束时,它的主函数所返回的值都将作为对应的resume的返回值。例如:

co6=coroutine.create(function()return 6, 7end)print("co6",coroutine.resume(co6))

 

非对称的协同程序(asymmetric coroutine):Lua提供了2个函数来控制协同程序的执行,一个用于挂起执行,另一个用于恢复执行。有人称之为“semi-coroutine”。

9.2协同程序与过滤器

一个关于协同程序的经典示例就是“生产者-消费者”的问题。

function producer()  while true do   local x=io.read()  --产生新的值  send(x)--发送给消费者  endendfunction consumer()  while true do   local x=receive()  --从生产者接收值  io.write(x, “\n”)--消费新的值  endend

 

协同程序被称为是一种匹配生产者和消费者的理想工具,一对resume-yield完全一改典型的调用者与被调用者之间的关系。当一个协同程序调用yield时,它不是进入一个新的函数,而是从一个悬而未决的resume调用中返回;同样对于resume的调用也不会启动一个新函数,而是从一次yield调用中返回。

消费者驱动(consumer-driven)模式:当消费者需要一个新值时,它唤醒生产者。

 

function receive()  local statue, value = coroutine.resume(producer)  return valueendfunction send(x)  coroutine.yield(x)end

 

过滤器(filter):是一种位于生产者和消费者之间的处理功能,可用于对数据的一些交换。

 

function filter(pro)  return coroutine.create(function()  for line=1, math.huge do  local x=receive(prod)  x=string.format(“%5d %s”, line, x)  send(x)  end  end )

 

9.3以协同程序实现迭代器

功能:遍历某个数组的所有排列组合的形式。

function permgen(a, n)n=n or #aif n<=1 thencoroutine.yield(a)--elsefor i=1, n doa[n], a[i]=a[i], a[n] --将第i个元素放到数组末尾permgen(a, n-1)--递归调用a[n], a[i]=a[i], a[n]  --恢复第i个元素endendend
 

定义一个工厂函数permutations,用于将生成函数放到一个协同程序中运行,并出具迭代器函数(只是简单地唤醒协同程序)。函数permutations是将一条唤醒协同程序的调用包装在一个函数中。

function permutations(a)local co=coroutine.create(function() permgen(a) end)return function()--迭代器local code, res=coroutine.resume(co) --开启return res--返回的res就是传入到函数permgen中的参数aendend
 
function printResult(a)for i=1, #a doio.write(a[i], " ")endio.write("\n")endfor p in permutations({1, 3, 5}) doprintResult(p)--调用打印函数end

 

9.4 非抢先式的(non-preemptive)多线程

协同程序提供了一种协作式的多线程,每个协同程序都等于一个线程。一对yield-resume可以将执行权在不同线程之间切换。有一点不同的就是:协同程序运行时是无法从外部停止它的,只有当协同程序显式地要求挂起时(调用yield),它才会停止。

对于非抢占式的多线程来说,只要一个线程调用一个阻塞(blocking)操作,整个程序在该操作完成前都会停止下来。但是这种行为对于大多数应用程序来说的无法接受的。

 

require "socket"  host="www.w3.org"file="/TR/REC-html32.html"--------------------------------------------------------------function receive(connection)  connection:settimeout(0)  local s, status, partial=connection:receive(2^10)  if status=="timeout" then  --coroutine.yield(connection)  end  return s or partial, statusend

 

函数的实现:

  function download(host, file)  打开一个TCP连接,连接到该站点的80端口  local c=assert(socket.connect(host, 80))  local count=0  返回一个连接对象,可以用它来发送文件请求  c:send("GET "..file.." HTTP/1.0\r\n\r\n")  while true do  local s, status, partial=receive(c)  count=count+#(s or partial)  if status=="closed" then  break  end  end  c:close()  print(file, count)  end


 

调用测试:
 
download(host, file)

 

第十章 完整的示例

10.1 数据描述

Lua作为一种数据描述语言。

要读取这些数据,程序只需简单地给出一个关于entry的合适定义,然后将数据文件作为一个程序来运行(通过dofile)。注意,必须对所有的条目遍历两次,第一次为获得标题列表,第二次为获得项目描述。

entry的定义如下:

 

  entry={  title="Tecgraf",  org="Computer Graphics ",  url="http://www.tecgraf.com",  contact="waldemar ...",  description=[[  Tecgraf is the result of ...  ]]  }

函数fwrite的实现:

 

  function fwrite(fmt, ...)  return io.write(string.format(fmt, ...))  end  function writeheader()  io.write([[  <html>  <head><title>Projects using Lua</title></head>  <body bgcolor="#FFFFFF">  Here are brief descriptions of Some Projects around  the world that use <a href="home.html">Lua</a>.  <br>  ]])  end

函数entry1的实现:

 

  function entry1(o)  count=count+1  local title=o.title or '(no title)'  fwrite('<li><a href="#%d">%s</a>', count, title)  end


函数entry2的实现:

 

  function entry2(o)  count=count+1  fwrite('<hr>\n<h3>\n')  local href=o.url and string.format(' href="%s", o.url') or ''  local title=o.title or o.org or 'org'  fwrite('<a name="%d"%s></a>\n', count, href, title)    if o.title and o.org then  fwrite('<br>\n<small><em>%s</em></small>', o.org)  end  fwrite('<\n</h3>>\n')      if o.description then  fwrite('%s<p>\n', string.gsub(o.description), '\n\n+', '<p>\n')  end    end

 

函数writetail的实现

 

  function writetail()  fwrite('</body></html>\n')  end

------------------------------------

测试代码如下:

  local inputfile='db.lua'  f=loadfile(inputfile)    writeheader()  count=0  entry=entry1  fwrite('<ul>\n')  f()  fwrite('</ul>\n')    count=0  entry=entry2  f()    writetail()

 

10.2 马尔可夫链(markov chain)算法

 

第一部分完

原创粉丝点击