Lua 協(xié)同程序(coroutine)與文件流操作

一、協(xié)同程序

Lua 協(xié)同程序(coroutine)與線程比較類似:擁有獨(dú)立的堆棧,獨(dú)立的局部變量,獨(dú)立的指令指針,同時又與其它協(xié)同程序共享全局變量和其它大部分東西。
協(xié)同是非常強(qiáng)大的功能,但是用起來也很復(fù)雜。
線程和協(xié)同程序區(qū)別
線程與協(xié)同程序的主要區(qū)別在于,一個具有多個線程的程序可以同時運(yùn)行幾個線程,而協(xié)同程序卻需要彼此協(xié)作的運(yùn)行。
在任一指定時刻只有一個協(xié)同程序在運(yùn)行,并且這個正在運(yùn)行的協(xié)同程序只有在明確的被要求掛起的時候才會被掛起。
協(xié)同程序有點(diǎn)類似同步的多線程,在等待同一個線程鎖的幾個線程有點(diǎn)類似協(xié)同。
協(xié)程的基本語法

image.png

演示

--1、定義協(xié)同函數(shù)coroutine.create
--2、啟動協(xié)同函數(shù)coroutine.resume
--3、暫停協(xié)同函數(shù)coroutine.yield
--4、繼續(xù)運(yùn)行coroutine.resume(不需要傳遞參數(shù)  )
--定義協(xié)同函數(shù)
co=coroutine.create(
function (a,b)
print(a+b)
print(coroutine.status(co))--查看協(xié)程狀態(tài) 這里是運(yùn)行狀態(tài)
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))--查看協(xié)程狀態(tài)  這里是暫停狀態(tài)

print("I'm here")
--res4表示繼續(xù)運(yùn)行后有返回值true,res5,res6是兩個返回值
res4,res5,res6=coroutine.resume(co)
print(res4,res5,res6)
print(coroutine.status(co))--查看協(xié)程狀態(tài)  這里是結(jié)束狀態(tài)

輸出結(jié)果:

50
running
true    20  1.073741824e+039
suspended
I'm here
-10
true    600 0.66666666666667
dead

coroutine.running就可以看出來,coroutine在底層實(shí)現(xiàn)就是一個線程。
當(dāng)create一個coroutine的時候就是在新線程中注冊了一個事件。
當(dāng)使用resume觸發(fā)事件的時候,create的coroutine函數(shù)就被執(zhí)行了,當(dāng)遇到y(tǒng)ield的時候就代表掛起當(dāng)前線程,等候再次resume觸發(fā)事件。
接下來我們分析一個更詳細(xì)的實(shí)例:

function foo (a)
    print("foo 函數(shù)輸出", a)
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end
 
co = coroutine.create(function (a , b)
    print("第一次協(xié)同程序執(zhí)行輸出", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("第二次協(xié)同程序執(zhí)行輸出", r)
    local r, s = coroutine.yield(a + b, a - b)  -- a,b的值為第一次調(diào)用協(xié)同程序時傳入
     
    print("第三次協(xié)同程序執(zhí)行輸出", r, s)
    return b, "結(jié)束協(xié)同程序"                   -- b的值為第二次調(diào)用協(xié)同程序時傳入
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("---分割線---")

輸出結(jié)果為:

第一次協(xié)同程序執(zhí)行輸出    1    10
foo 函數(shù)輸出    2
main    true    4
--分割線----
第二次協(xié)同程序執(zhí)行輸出    r
main    true    11    -9
---分割線---
第三次協(xié)同程序執(zhí)行輸出    x    y
main    true    10    結(jié)束協(xié)同程序
---分割線---
main    false    cannot resume dead coroutine
---分割線---

運(yùn)行分析:
(1)調(diào)用resume,將協(xié)同程序喚醒,resume操作成功返回true,否則返回false;
協(xié)同程序運(yùn)行;
(2)運(yùn)行到y(tǒng)ield語句;yield掛起協(xié)同程序,第一次resume返回;(注意:此處yield返回,參數(shù)是resume的參數(shù))
(2)第二次resume,再次喚醒協(xié)同程序;(注意:此處resume的參數(shù)中,除了第一個參數(shù),剩下的參數(shù)將作為yield的參數(shù))
(3)yield返回;
(4)協(xié)同程序繼續(xù)運(yùn)行;
(5)如果使用的協(xié)同程序繼續(xù)運(yùn)行完成后繼續(xù)調(diào)用 resume方法則輸出:cannot resume dead coroutine

resume和yield的配合強(qiáng)大之處在于,resume處于主程中,它將外部狀態(tài)(數(shù)據(jù))傳入到協(xié)同程序內(nèi)部;而yield則將內(nèi)部的狀態(tài)(數(shù)據(jù))返回到主程中。

二、文件流操作

Lua I/O 庫用于讀取和處理文件。分為簡單模式(和C一樣)、完全模式。
簡單模式(simple model)擁有一個當(dāng)前輸入文件和一個當(dāng)前輸出文件,并且提供針對這些文件相關(guān)的操作。
完全模式(complete model) 使用外部的文件句柄來實(shí)現(xiàn)。它以一種面對對象的形式,將所有的文件操作定義為文件句柄的方法
簡單模式在做一些簡單的文件操作時較為合適。但是在進(jìn)行一些高級的文件操作的時候,簡單模式就顯得力不從心。例如同時讀取多個文件這樣的操作,使用完全模式則較為合適。

image.png
簡單模式下文本的寫入:
做一個例子,例如創(chuàng)建一個空的txt文件命名為Data.txt,然后我們在Lua中去操作這個文本文件,首先用a模式去寫入文本,然后用r模式可以去讀取文本,最后可以用w模式去修改文本,例子如下

--a模式
--以附加的方式打開只寫文件
--若文件不存在,則會建立該文件,
--如果文件存在,寫入的數(shù)據(jù)會被加到文件尾
--即文件原先的內(nèi)容會被保留
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)--表示對文件進(jìn)行操作
print(io.read())--只讀取第一行內(nèi)容
print(io.read())
print(io.read())
io.close(file)

--w模式
--打開只寫文件,若文件存在則文件長度清為0
--即該文件內(nèi)容會消失。再重新寫入新內(nèi)容
file=io.open("Data.txt","w")
io.output(file)
io.write("Name:Jess\nArg:16\nCity:ShangHai")
io.close()

最后在lua中輸出結(jié)果

Name:Danni
Arg:18
City:ShenZhen

再去查看文本中的內(nèi)容為

Name:Jess
Arg:16
City:ShangHai

讀取文件的一些參數(shù)功能

image.png
其他的 io 方法有:
io.tmpfile():返回一個臨時文件句柄,該文件以更新模式打開,程序結(jié)束時自動刪除
io.type(file): 檢測obj是否一個可用的文件句柄
io.flush(): 向文件寫入緩沖中的所有數(shù)據(jù)
io.lines(optional file name): 返回一個迭代函數(shù),每次調(diào)用將獲得文件中的一行內(nèi)容,當(dāng)?shù)轿募矔r,將返回nil,但不關(guān)閉文件

下面我們來測試一下讀取文件的參數(shù)有什么用

file= io.open("Data.txt","r")
io.input(file)
print(io.read("*a"))--讀取文本中所有內(nèi)容
--print(io.read("*l"))--讀取默認(rèn) 只讀取第一行內(nèi)容
--print(io.read(5))--讀取文本中5個內(nèi)容
io.close(file)

輸出

Name:Jess
Arg:16
City:ShangHai

完全模式下文本的寫入:
通常我們需要在同一時間處理多個文件。我們需要使用 file:function_name 來代替 io.function_name 方法。以下實(shí)例演示了如同同時處理同一個文件:
完全模式和簡單模式相差不多,大部分的方法都差不多,只有一下結(jié)構(gòu)方面不同,下面我們來測試看看,只需要把Io.read或者io.write改成file:read或者file:write就OK了

file= io.open("Data.txt","r")
print(file:read("*a"))--讀取文本中所有內(nèi)容
--print(io.read("*l"))--讀取默認(rèn) 只讀取第一行內(nèi)容
--print(io.read(5))--讀取文本中5個內(nèi)容
io.close(file)

輸出結(jié)果

Name:Jess
Arg:16
City:ShangHai
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容