Lua 协同程序(coroutine)与文件流操作

一、协同程序

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
协同是非常强大的功能,但是用起来也很复杂。
线程和协同程序区别
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
协程的基本语法

image.png

演示

--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) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。

image.png
简单模式下文本的写入:
做一个例子,例如创建一个空的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

读取文件的一些参数功能

image.png
其他的 io 方法有:
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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容