一、协同程序
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
协同是非常强大的功能,但是用起来也很复杂。
线程和协同程序区别
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
协程的基本语法
演示
--1、定义协同函数coroutine.create
--2、启动协同函数coroutine.resume
--3、暂停协同函数coroutine.yield
--4、继续运行coroutine.resume(不需要传递参数 )
--定义协同函数
co=coroutine.create(
function (a,b)
print(a+b)
print(coroutine.status(co))--查看协程状态 这里是运行状态
coroutine.yield(a%b,a^b)
print(a-b)
return a*b,a/b
end
)
--res1表示在挂起的时候有返回值true,res2和res3是返回的两个值
res1,res2,res3=coroutine.resume(co,20,30)--res1,res2,res3接收返回值
print(res1,res2,res3)
print(coroutine.status(co))--查看协程状态 这里是暂停状态
print("I'm here")
--res4表示继续运行后有返回值true,res5,res6是两个返回值
res4,res5,res6=coroutine.resume(co)
print(res4,res5,res6)
print(coroutine.status(co))--查看协程状态 这里是结束状态
输出结果:
50
running
true 20 1.073741824e+039
suspended
I'm here
-10
true 600 0.66666666666667
dead
coroutine.running就可以看出来,coroutine在底层实现就是一个线程。
当create一个coroutine的时候就是在新线程中注册了一个事件。
当使用resume触发事件的时候,create的coroutine函数就被执行了,当遇到yield的时候就代表挂起当前线程,等候再次resume触发事件。
接下来我们分析一个更详细的实例:
function foo (a)
print("foo 函数输出", a)
return coroutine.yield(2 * a) -- 返回 2*a 的值
end
co = coroutine.create(function (a , b)
print("第一次协同程序执行输出", a, b) -- co-body 1 10
local r = foo(a + 1)
print("第二次协同程序执行输出", r)
local r, s = coroutine.yield(a + b, a - b) -- a,b的值为第一次调用协同程序时传入
print("第三次协同程序执行输出", r, s)
return b, "结束协同程序" -- b的值为第二次调用协同程序时传入
end)
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")
输出结果为:
第一次协同程序执行输出 1 10
foo 函数输出 2
main true 4
--分割线----
第二次协同程序执行输出 r
main true 11 -9
---分割线---
第三次协同程序执行输出 x y
main true 10 结束协同程序
---分割线---
main false cannot resume dead coroutine
---分割线---
运行分析:
(1)调用resume,将协同程序唤醒,resume操作成功返回true,否则返回false;
协同程序运行;
(2)运行到yield语句;yield挂起协同程序,第一次resume返回;(注意:此处yield返回,参数是resume的参数)
(2)第二次resume,再次唤醒协同程序;(注意:此处resume的参数中,除了第一个参数,剩下的参数将作为yield的参数)
(3)yield返回;
(4)协同程序继续运行;
(5)如果使用的协同程序继续运行完成后继续调用 resume方法则输出:cannot resume dead coroutine
resume和yield的配合强大之处在于,resume处于主程中,它将外部状态(数据)传入到协同程序内部;而yield则将内部的状态(数据)返回到主程中。
二、文件流操作
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。
做一个例子,例如创建一个空的txt文件命名为Data.txt,然后我们在Lua中去操作这个文本文件,首先用a模式去写入文本,然后用r模式可以去读取文本,最后可以用w模式去修改文本,例子如下
--a模式
--以附加的方式打开只写文件
--若文件不存在,则会建立该文件,
--如果文件存在,写入的数据会被加到文件尾
--即文件原先的内容会被保留
file=io.open("Data.txt","a")
io.output(file)
io.write("Name:Danni\nArg:18\nCity:ShenZhen")
io.close()
--r模式
--以只读方式打开文件,该文件必须存在。
file= io.open("Data.txt","r")
io.input(file)--表示对文件进行操作
print(io.read())--只读取第一行内容
print(io.read())
print(io.read())
io.close(file)
--w模式
--打开只写文件,若文件存在则文件长度清为0
--即该文件内容会消失。再重新写入新内容
file=io.open("Data.txt","w")
io.output(file)
io.write("Name:Jess\nArg:16\nCity:ShangHai")
io.close()
最后在lua中输出结果
Name:Danni
Arg:18
City:ShenZhen
再去查看文本中的内容为
Name:Jess
Arg:16
City:ShangHai
读取文件的一些参数功能
io.tmpfile():返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除
io.type(file): 检测obj是否一个可用的文件句柄
io.flush(): 向文件写入缓冲中的所有数据
io.lines(optional file name): 返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,但不关闭文件
下面我们来测试一下读取文件的参数有什么用
file= io.open("Data.txt","r")
io.input(file)
print(io.read("*a"))--读取文本中所有内容
--print(io.read("*l"))--读取默认 只读取第一行内容
--print(io.read(5))--读取文本中5个内容
io.close(file)
输出
Name:Jess
Arg:16
City:ShangHai
完全模式下文本的写入:
通常我们需要在同一时间处理多个文件。我们需要使用 file:function_name 来代替 io.function_name 方法。以下实例演示了如同同时处理同一个文件:
完全模式和简单模式相差不多,大部分的方法都差不多,只有一下结构方面不同,下面我们来测试看看,只需要把Io.read或者io.write改成file:read或者file:write就OK了
file= io.open("Data.txt","r")
print(file:read("*a"))--读取文本中所有内容
--print(io.read("*l"))--读取默认 只读取第一行内容
--print(io.read(5))--读取文本中5个内容
io.close(file)
输出结果
Name:Jess
Arg:16
City:ShangHai