Java代码中与Lua相互调用实现详解

目录
  • 一、方案
  • 二、性能测试
    • 1. ScriptEngine调用方式
    • 2. Globals调用方式
    • 3. lua调用java
  • 三、结论
  • 四、其他调用方式?

一、方案

Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。

目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的小伙伴欢迎关注下。

目前最常见的方案:luaj,纯Java实现的Lua解析器,基于Lua 5.2

LuaJ的原理:用Java实现了一套Lua的编译器,本质上是把Lua文件中的Lua语言动态编译成了Java字节码,因此会收到诸多限制(比如第三方库的问题),而LuaJ本质上也只是运行在JVM上的Java字节码,和运行在C编译器环境下的Lua是有区别的

Maven pom

虽然源码已有3.0.2版本,但作者未上传maven,如有需要,可以自行导入jar包(源码中已打好3.0.2的jar包)

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

二、性能测试

以下我们以最基本的for循环并执行加法操作为例,分别在java外部for一万次,并在lua内部再for一万次

java原生代码

原生代码执行时间:1ms ~ 2ms

private static void runJava(int iterNum) {
    beg = System.currentTimeMillis();
    for (int j = 0; j &lt; iterNum; j++) {
        int a = 0;
        for (int i = 0; i &lt; 10000; i++) {
            a = a + i;
        }
    }
    end = System.currentTimeMillis();
}

lua脚本

function test()
    a = 0;
    for i = 0, 10000, 1 do
        a = a + i;
    end
end

1. ScriptEngine调用方式

调用方式:外部10000次调用,lua内部10000次循环a++ 总时间:8.9s左右 平均一次lua方法调用(1w次a++):0.89ms lua内部一次循环调用(1次a++):0.000089ms 修改lua内部循环1次 时间:10ms 平均一次lua方法调用:0.001ms

// ==================================================================================
// ScriptEngine方式
// ==================================================================================
Reader reader = new FileReader(luaStr);
LuaScriptEngine luaScriptEngine = (LuaScriptEngine) new LuaScriptEngineFactory().getScriptEngine();
// 使用luajc编译器,比默认luac编译器快3倍
LuajContext context = (LuajContext) luaScriptEngine.getContext();
LuaJC.install(context.globals);
CompiledScript compiledScript = luaScriptEngine.compile(reader);
Bindings bindings = new SimpleBindings();
compiledScript.eval(bindings);
LuaFunction luafunc = (LuaFunction) bindings.get("test");
beg = System.currentTimeMillis();
for (int i = 0; i &lt; iterNum; i++) {
    luafunc.call();
}
end = System.currentTimeMillis();
// ==================================================================================

2. Globals调用方式

调用方式:外部10000次调用,lua内部10000次循环a++ 时间:2.3s左右 平均一次lua方法调用:0.23ms lua内部一次循环调用:0.000023ms 修改lua内部循环1次 时间:4ms 平均一次lua方法调用:0.0004ms

// ==================================================================================
// Global方式
// ==================================================================================
Globals globals = JsePlatform.standardGlobals();
// 使用luajc编译器,比默认luac编译器快3倍
LuaJC.install(globals);
LuaValue doFile = globals.get("dofile");
doFile.call(LuaValue.valueOf(luaStr));
LuaValue luaValue = globals.get("test");
beg = System.currentTimeMillis();
for (int i = 0; i &lt; iterNum; i++) {
    luaValue.call();
}
end = System.currentTimeMillis();
  1w*1w调用总时间 平均一次lua脚本时间 lua内部一次循环时间
Java 1ms-2ms - -
ScriptEngine 8.9s 0.89ms 0.000089ms
Globals 2.3s 0.23ms 0.000023ms

3. lua调用java

把lua内的循环10000次,挪到java方法执行,java for(10000) -> lua -> java for(10000)

function test()
    luaTestJava:javaLoop()
end

Java提供loop方法

public static void javaLoop() {
    int a = 0;
    for (int i = 0; i < 10000; i++) {
        a = a + i;
    }
}

Global调用方式:5ms ScriptEngine调用方式:30ms

三、结论

  • luaj没有jit
  • 目前看来,在luaJ这个方案下,Globals的调用方式速度最快
  • 同样的代码,在lua执行和在java执行始终是有差距的,lua执行就是比java执行慢很多 后经过分析源码,发现luaj的每一次++操作,都会new出LuaValue对象,经过dump也发现测试中的LuaValue对象创建非常多
  • luaJ的实现相对完整,lua和java可以相互调用,相互传参

作者的文档里说,某些情况下,luajc编译模式的效率和基于C的lua效率差不多源码中的示例

四、其他调用方式?

脱离java环境的lua编译器,lua单独运行进程,提供服务,java跨进程调用服务(没有尝试过,不知道跨进程调用掉率如何,也不知道lua进程资源占用情况) 这样lua可以使用luajit,也不受版本限制(luaJ是5.2)

以上就是Java代码中与Lua相互调用实现详解的详细内容,更多关于Java代码与Lua相互调用的资料请关注我们其它相关文章!

(0)

相关推荐

  • springboot中使用redis并且执行调试lua脚本

    目录 原因: 1.创建一个基本的web项目 2.配置redis 3.测试redis 的lua脚本 4.技术点 5.调试方式 1.进入服务关闭关闭正在运行的服务器 2.从命令行启动redis 3.在lua脚本中增加打印 4.运行代码 6.总结 今天有个项目需要使用redis,并且有使用脚本的需求.但是因为之前没有写过,所以还有一点点不熟悉,今天记录一下. 原因: 原子操作,redis会将整个脚本作为一个整体执行,中间不会被其他命令插入. 1.创建一个基本的web项目 文件 ->新建 -> 项目,

  • springboot使用redisTemplate操作lua脚本

    目录 写在前面 使用lua 解释 写在前面 操作redis使用Lua脚本有诸多好处 减少网络开销:可以将多个请求通过脚本的形式一次发送,减少网络时延和请求次数. 原子性的操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入.因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务. 代码复用:客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本来完成相同的逻辑. 速度快:见 与其它语言的性能比较, 还有一个 JIT编译器可以显著地提高多数任务的性能; 对于那

  • SpringBoot+Redis+Lua分布式限流的实现

    Redis支持LUA脚本的主要优势 LUA脚本的融合将使Redis数据库产生更多的使用场景,迸发更多新的优势: 高效性:减少网络开销及时延,多次redis服务器网络请求的操作,使用LUA脚本可以用一个请求完成 数据可靠性:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入. 复用性:LUA脚本执行后会永久存储在Redis服务器端,其他客户端可以直接复用 可嵌入性:可嵌入JAVA,C#等多种编程语言,支持不同操作系统跨平台交互 简单强大:小巧轻便,资源占用率低,支持过程化和对象化的编程

  • SpringBoot通过RedisTemplate执行Lua脚本的方法步骤

    lua 脚本 Redis 中使用 lua 脚本,我们需要注意的是,从 Redis 2.6.0后才支持 lua 脚本的执行. 使用 lua 脚本的好处: 原子操作:lua脚本是作为一个整体执行的,所以中间不会被其他命令插入. 减少网络开销:可以将多个请求通过脚本的形式一次发送,减少网络时延. 复用性:lua脚本可以常驻在redis内存中,所以在使用的时候,可以直接拿来复用,也减少了代码量. 1.RedisScript 首先你得引入spring-boot-starter-data-redis依赖,其

  • springboot中通过lua脚本来获取序列号的方法

    序言: 事件:此web项目的功能及其简单,就是有客户端来访问redis序列号服务时发送jison报文,项目已经在测试环境成功运行2周了,具体的代码我就直接上了,此博客仅是自己的记录,同学们可做参考! 一.工程目录结构 二.配置文件 1.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"

  • 详解springboot+aop+Lua分布式限流的最佳实践

    一.什么是限流?为什么要限流? 不知道大家有没有做过帝都的地铁,就是进地铁站都要排队的那种,为什么要这样摆长龙转圈圈?答案就是为了限流!因为一趟地铁的运力是有限的,一下挤进去太多人会造成站台的拥挤.列车的超载,存在一定的安全隐患.同理,我们的程序也是一样,它处理请求的能力也是有限的,一旦请求多到超出它的处理极限就会崩溃.为了不出现最坏的崩溃情况,只能耽误一下大家进站的时间. 限流是保证系统高可用的重要手段!!! 由于互联网公司的流量巨大,系统上线会做一个流量峰值的评估,尤其是像各种秒杀促销活动,

  • Java代码中与Lua相互调用实现详解

    目录 一.方案 二.性能测试 1. ScriptEngine调用方式 2. Globals调用方式 3. lua调用java 三.结论 四.其他调用方式? 一.方案 Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试. 目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的小伙伴欢迎关注下. 目前最常见的方案:luaj,纯Java实现的Lua解析器,基于Lua 5.2 LuaJ的原理:用Java实现了一套Lua的编译器

  • java线程中start和run的区别详解

    这篇文章主要介绍了java线程中start和run的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 public class Test1 extends Thread { @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName()); } } public static void main(String[

  • Java开发中synchronized的定义及用法详解

    概念 是利用锁的机制来实现同步的. 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问.互斥性我们也往往称为操作的原子性. 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致. 用法 修饰静态方法: //同步静态方法 public synchronized

  • java迭代器中删除元素的实例操作详解

    我们知道通过Iterator,可以对集合中的元素进行遍历.那么在其中遇到我们不需要的元素时,可不可以在遍历的时候顺便给删除呢?答案是当然可以.在Iterator下有一个remove函数,专门用于删除的操作.下面我们就remove进行讲解,然后对删除元素方法进行说明,最后带来实例的展示. 1.Iterator中的remove void remove():删除迭代器刚越过的元素 从基础集合中移除这个迭代器返回的最后一个元素(可选操作).两个线程中都删除,保证线程的同步. 2.删除元素说明 (1)迭代

  • Java并发中的Fork/Join 框架机制详解

    什么是 Fork/Join 框架 Fork/Join 框架是一种在 JDk 7 引入的线程池,用于并行执行把一个大任务拆成多个小任务并行执行,最终汇总每个小任务结果得到大任务结果的特殊任务.通过其命名也很容易看出框架主要分为 Fork 和 Join 两个阶段,第一阶段 Fork 是把一个大任务拆分为多个子任务并行的执行,第二阶段 Join 是合并这些子任务的所有执行结果,最后得到大任务的结果. 这里不难发现其执行主要流程:首先判断一个任务是否足够小,如果任务足够小,则直接计算,否则,就拆分成几个

  • java 并发中的原子性与可视性实例详解

    java 并发中的原子性与可视性实例详解 并发其实是一种解耦合的策略,它帮助我们把做什么(目标)和什么时候做(时机)分开.这样做可以明显改进应用程序的吞吐量(获得更多的CPU调度时间)和结构(程序有多个部分在协同工作).做过java Web开发的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用单实例多线程的工作模式,Servlet容器为你处理了并发问题. 原子性 原子是世界上的最小单位,具有不可分割性.比如 a=0:(a非long和double类型) 这个操作是不

  • Java Mybatis中的 ${ } 和 #{ }的区别使用详解

    好了,真正做开发也差不多一年了.一直都是看别人的博客,自己懒得写,而且也不会写博客,今天就开始慢慢的练习一下写博客吧.前段时间刚好在公司遇到这样的问题. 一.举例说明 select * from user where name = "dato"; select * from user where name = #{name}; select * from user where name = '${name}'; 一般情况下,我们都不会注意到这里面有什么不一样的地方.因为这些sql都可以

  • Java 9中如何对IntegerCache进行修改详解

    在开始本文的正文之前,我们下面来看看下面这段代码: Java中Integer类的IntegerCache的作用 包名:java.lang 文件名:Integer.java 方法名:IntegerCache 方法的代码如下: private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may

  • Java集合中的fail-fast(快速失败)机制详解

    简介 我们知道Java中Collection接口下的很多集合都是线程不安全的, 比如 java.util.ArrayList不是线程安全的, 因此如果在使用迭代器的过程中有其他线程修改了list,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略. 这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 exp

  • Java线程中的关键字和方法示例详解

    目录 一.volatile关键字 1,volatile能保证内存可见性 2,编译器优化问题 二.wait和notify 1,wait()方法 2,notify()方法 3,notifyAll()方法 一.volatile关键字 1,volatile 能保证内存可见性 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值 将改变后的副本的值从工作内存刷新到主内存 代码在读取 volatile 修饰的变量的时候 从主内存中读取volatile变量的最新值到线

随机推荐