zoukankan      html  css  js  c++  java
  • Lua学习笔记4. coroutine协同程序和文件I/O、错误处理

    Lua学习笔记4. coroutine协同程序和文件I/O、错误处理

    Lua 的协同程序coroutine和线程比较类似,有独立的堆栈、局部变量、独立的指针指令,同时又能共享全局变量
    但coroutine又和多线程程序不同,首先一个多线程程序可以同时运行多个单线程,但协同程序只能串行,也就是说同一时刻只能有一个协同程序在运行,并且这个协同程序将一直占用处理器直到被显式的挂起。

    基本的函数

    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

    生产者-消费者问题

    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的文件输入输出包含两种模式 简单模式和完全模式
    简单模式

    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)
    

    复杂模式

    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的模式有

    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") .."
    errMessage:"..(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").."
    errMessage:"..(errMessage or "null"))
    end
    
        print("
    ---------A---------
    ")
        tryCatch(f)
        print("
    ---------B---------
    ")
        xTryCatch(f)
        print("
    ---------C---------
    ")
    

    输出

    ---------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
    
  • 相关阅读:
    tomcat启动项目,起不起来
    jQuery ajax 获取信息展示在“下拉列表”中
    JQuery,ajax,jsonp 跨域访问
    httpwebrequest详解
    利用HttpWebRequest和HttpWebResponse获取Cookie并实现模拟登录
    C# 中使用System.Net.Http.HttpClient 模拟登录博客园 (GET/POST)
    JAVA-用HttpClient来模拟浏览器GET,POST
    java 实现模拟浏览器 访问网站
    ora-01017 和oracle database link
    JDeveloper 开发环境配置
  • 原文地址:https://www.cnblogs.com/YiXiaoZhou/p/6286824.html
Copyright © 2011-2022 走看看