• Java调用Lua脚本(热载实现)


    前言:
      Lua作为解析执行的脚本语言, 往往是易变逻辑编写的首选语言, 尤其是在游戏领域. C/C++和Lua的结合, 往往了标配. 比如Redis, Nginx其对Lua的支持, 也是杠杠的. 当然Lua也可以作为规则引擎中的规则编写语言. 本文对Java调用Lua(Luaj)的实现机制, 做下简单的介绍.

    Luaj简介:
      Luaj是Java调用Lua的一种实现方式, 其是构建一个虚拟机解析执行Lua脚本来实现的, 这和Groovy的方式有所不同.
      这是Luaj的官网, http://www.luaj.org/luaj/3.0/README.html.
      它是针对5.2.x的lua版本的解析器, 其Luaj库的编写是通过JavaCC来实现的.

    简单示例:
      集合Luaj, 可以通过Maven进行如下配置:

            <dependency>
                <groupId>org.luaj</groupId>
                <artifactId>luaj-jse</artifactId>
                <version>3.0.1</version>
            </dependency>

      Luaj的一个简单的示例程序:

    import org.luaj.vm2.Globals;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    public class TestLuaJ {
    
    
        public static void main(String[] args) {
    
            String luaStr = "print 'hello,world!'";
            Globals globals = JsePlatform.standardGlobals();
            LuaValue chunk = globals.load(luaStr);
            chunk.call();
    
        }
    
    }

      注: Globals继承LuaValue对象,LuaValue对象用来表示在Lua语言的基本数据类型,比如:Nil,Number,String,Table,userdata,Function等。尤其要注意LuaValue也表示了Lua语言中的函数。所以,对于Lua语言中的函数操作都是通过LuaValue来实现的.
      其输出的结果:

    hello,world!

    原理初探:
      根据官方的说法, Luaj在包装执行具体的Lua代码时, 有三种不同的模式.
      1). 纯脚本解析执行(不选用任何Compiler)
      2). To Lua字节码(LuaC, lua-to-lua-bytecode compiler)
      3). To Java字节码(LuaJC, lua-to-java-bytecode compiler)
      其中LuaC是默认的选用Compiler.
      依据官方的介绍:
      不使用LuaC的方法是, 则不调用如何行:

    org.luaj.vm2.compiler.LuaC.install(globals);

      而使用LuaJC的方法, 则是调用

    org.luaj.vm2.jse.luajc.LuaJC.install(globals);

      可惜, 笔者在自己测试过程中, 遇到了异常(org.luaj.vm2.LuaError: No compiler.), 好尴尬:
      

    性能评估:
      对Lua解析的代码进行简单的性能评估:
      其对同样的逻辑代码:

                int a = 0;
                for ( int i = 0; i < 10000; i++ ) {
                    a = a + i;
                }

      执行10000次, 具体对比耗时值.
      整体的测试代码如下:

    import org.luaj.vm2.Globals;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    public class TestLuaJPerf {
    
        public static void main(String[] args) {
    
            int iterNum = 10000;
    
            // *) java 模式运行
            long beg = System.currentTimeMillis();
            for ( int j = 0; j < iterNum; j++ ) {
                int a = 0;
                for ( int i = 0; i < 10000; i++ ) {
                    a = a + i;
                }
            }
            long end = System.currentTimeMillis();
            System.out.println(String.format("Java consume: %dms", end - beg));
    
            // *) Lua脚本解析执行
            String luaStr = "a = 0; for i = 0, 10000, 1 do a = a + i; end";
            Globals globals = JsePlatform.standardGlobals();
            LuaValue chunk = globals.load(luaStr);
            beg = System.currentTimeMillis();
            for ( int i = 0; i < iterNum; i++ ) {
                chunk.call();
            }
            end = System.currentTimeMillis();
            System.out.println(String.format("Lua consume: %dms", end - beg));
    
        }
    
    }

      测试结果如下:

    Java consume: 10ms
    Lua consume: 10249ms

      几乎1000倍的差异, 这个性能对比, 差异有些大, Lua确实慢的不止半点(可能和Luaj的具体实现也有些关系), 因此从这方面来说, Java+Groovy的结合, 比Java+Lua的结合更有优势.


    线程安全:
      Luaj中的Globals对象不是线程安全的, 因此最佳实践是每个线程一个Globals对象.
      事实上, 可以采用ThreadLocal的方式来存储该对象.
      因为是对象, 而不是Class, 其和Groovy编译的Script类, 其实现思路是本质区别的.

    总结:
      个人对Luaj的认识还是有些肤浅, 没有深入地去研究, 所以可能这边的一些结论可能不准确. 同时Luaj对Lua脚本的支持, 到什么程度, 其实也是一个问号. 不管怎么样, 能对Luaj能有一个初步的认识, 也是好事.

  • 相关阅读:
    java设计模式-----3、抽象工厂模式
    java设计模式-----2、工厂方法模式
    java设计模式-----1、简单工厂模式
    解决windows10和ubuntu16.04双系统下时间不对的问题
    个人第二次作业-熟悉使用工具成绩汇总
    第二周助教小结——工作步入正轨
    第一周助教小结——助教工作初体验
    助教培训总结——熟练掌握GitHub及Git的使用方法
    助教培训总结——原型设计工具及练习
    助教培训总结——对学生任务博客的评分练习
  • 原文地址:https://www.cnblogs.com/mumuxinfei/p/8474251.html
Copyright © 2020-2023  润新知