Lua學習筆記4. coroutine協同程序和文件I/O、錯誤處理

Lua學習筆記4. coroutine協同程序和文件I/O、錯誤處理

Lua 的協同程序coroutine和線程比較相似,有獨立的堆棧、局部變量、獨立的指針指令,同時又能共享全局變量
但coroutine又和多線程程序不一樣,首先一個多線程程序能夠同時運行多個單線程,但協同程序只能串行,也就是說同一時刻只能有一個協同程序在運行,而且這個協同程序將一直佔用處理器直到被顯式的掛起。web

基本的函數緩存

coroutine.create(f)         建立一個協同程序,返回coroutine, f是該協同程序的註冊函數
coroutine.yield(a)          將當前運行的coroutine掛起,a是掛起後返回的值或表達式結果
coroutine.resume(co,a,...)  喚醒coroutine co,後面的a,...是對應註冊函數待輸入的參數,返回一個布爾值表示是否喚醒成功
coroutine.status(co)        返回協同程序co的狀態,協同程序的狀態包括dead,suspend和running
coroutine.running()         返回當前正在運行的coroutine的線程號和一個boolean值表示是否是主線程

看個例子多線程

function foo(a)
    print("foo 的函數輸出 ", a)
    return coroutine.yield(2*a)
end

co=coroutine.create(function(a,b)
    print("第一次協同程序執行輸出",a,b)
    local r=foo(a+1)
    a=a+1
    print("第二次協同程序輸出",r)
    local r,s=coroutine.yield(a+b,a-b)

    print("第三次協同程序執行輸出",r,s)
    return b
    end
)

print('main',coroutine.resume(co,1,10))
print('--------分割線--------')
print('main',coroutine.resume(co))
print('--------分割線--------')
print("main",coroutine.resume(co,"x","y"))
print("--------分割線--------")
print("main",coroutine.resume(co,"x","y"))
print("--------分割線--------")

其輸出函數

第一次協同程序執行輸出 1   10
foo 的函數輸出   2
main    true    4
--------分割線--------
第二次協同程序輸出   nil
main    true    12  -8
--------分割線--------
第三次協同程序執行輸出 x   y
main    true    10
--------分割線--------
main    false   cannot resume dead coroutine
--------分割線--------

分析一下:首先執行到print('main',coroutine.resume(co,1,10))這一行先執行裏面做爲參數的函數,即喚醒協同程序co,進入了對應的註冊函數,輸出一句,而後進入函數foo,foo的參數爲1,10
執行foo裏面的第一句輸出,而後返回 掛起線程操做的狀態,以及對應的返回值,這裏就是2*a
OK,這時候又回到了主線程,輸出 main 狀態 返回參數
輸出分割線
喚醒co,這個時候從上次掛起的階段繼續執行,此時resume的參數是coroutine.yield()的參數做爲返回值
。。。
最後若是co已經dead,則輸出false,即喚醒失敗,和cannot resume dead coroutine的信息,若是這個時候想再執行註冊函數的內容須要從新建立coroutine學習

生產者-消費者問題ui

local newProductor function productor() local i=0
    while i<10 do
        i=i+1
        send(i)
    end end function consumer() repeat local i=receive()
        print(i)
    until i>9
end function receive() local status,value=coroutine.resume(newProductor)
    return value end function send(x) coroutine.yield(x) end newProductor=coroutine.create(productor)
consumer()

I/O

lua的文件輸入輸出包含兩種模式 簡單模式和徹底模式
簡單模式lua

file = io.open("moduleTest.lua",'r')
io.input(file)
print(io.read())
io.close(file)
file=io.open("moduleTest.lua","a+")
io.output(file)
io.write("This is a sentense written in simple model")
io.close(file)

複雜模式spa

file=io.open("moduleTest.lua","a+")
print(file:read())
file:close()
file=io.open("moduleTest.lua","a")
file:write("This sentence is written in complete model")
file:close

不一樣點在於簡單模式須要指定輸入輸出設備,而徹底模式直接經過文件句柄操做。線程

文件open的模式有debug

r           只讀模式,文件必須存在
w           清零重寫模式,若是沒有則新建
a           附加模式,沒有則新建
r+          讀寫模式,文件必須存在
w+          和w相似,可是可讀寫
a+          和a相似,可是可讀寫
b           二進制模式,若是文件是二進制文件,可在上面的模式符後添加b

read()的參數有

空                  讀取一行
"*n"                讀取一個數字
"*a"                從當前位置讀取整個文件
"*l"(默認)          都去下一行,文件結尾處返回nil
number              讀取指定個數個字符,EOF時返回nil

io其餘方法

io.tmpfile()    返回一個臨時文件句柄,該文件以更新模式打開,程序結束時自動刪除
io.type(file)   檢測file是否是可用的文件句柄
io.flush()      向文件中寫入緩存區中全部數據
io.lines(optional filename)     返回一個由line組成的迭代器,文件結尾時返回nil,但不關閉文件
e.g. 
for line in io.lines("moduleTest.lua") do 
    print(line)
end

file的read,write,lines,close等方法和io相似,只不過使用的是":"符號

file的其餘方法

file:seek(optional whence,optional offset)  設定當前位置,第二個參數是偏置
第一個參數可選
"set"       文件頭
"cur"       當前位置(默認)
"end"       文件尾
不帶參數,file:seek()返回當前位置

file:flush()        將緩衝區全部數據寫入文件
file:lines()        相似於io.lines(filename)返回一個迭代器,只是此處沒有輸入參數

錯誤處理

  1. 斷言assert(arg1,arg2),首先檢查第一個參數,沒問題ok,有問題將第二個參數做爲錯誤信息拋出

  2. error(message[,level]),終止執行的函數,拋出message做爲錯誤信息
    level表示附加的錯誤位置信息
    level=1,error的位置
    level=2,調用error的函數
    level=0,不添加錯誤位置信息

  1. 相似於trycatch語句pcall,xpcall
    調用格式:
    pcall(f[,arg]) --f是protect call的函數,arg是f的參數
    xpcall(f,errHandleFun[,arg]) --errHandleFun是錯誤處理函數

相同點:
當程序正常執行時,都返回true和被執行函數f的返回值
不一樣點:
i. pcall: 返回錯誤信息時,已經釋放了保存錯誤發生狀況的棧信息
xpcall: 在釋放棧信息以前調用錯誤處理程序處理這些信息
ii. pcall:返回nil,錯誤信息
xpcall:返回nil,無錯誤信息

local f=function(...)
        --local a=1
        print (a+1)
        return a+1
    end

tryCatch = function(f)
        local ret,errMessage=pcall(f)
        print("ret:" ..(ret and "true" or "false") .."\nerrMessage:"..(errMessage or "null"))
end

xTryCatchGetErrorInfo=function()
            print(debug.traceback())
        end

xTryCatch=function(f)
    local ret,errMessage=xpcall(f,xTryCatchGetErrorInfo)
    print("ret:"..(ret and "true" or "false").."\nerrMessage:"..(errMessage or "null"))
end

    print("\n---------A---------\n")
    tryCatch(f)
    print("\n---------B---------\n")
    xTryCatch(f)
    print("\n---------C---------\n")

輸出

---------A---------

ret:false
errMessage:testIO.lua:18: attempt to perform arithmetic on global 'a' (a nil value)

---------B---------

stack traceback:
    testIO.lua:28: in function <testIO.lua:27>
    testIO.lua:18: in function <testIO.lua:16>
    [C]: in function 'xpcall'
    testIO.lua:32: in function 'xTryCatch'
    testIO.lua:39: in main chunk
    [C]: ?
ret:false
errMessage:null

---------C---------

>Exit code: 0
相關文章
相關標籤/搜索