groovy脚本eval(string)方法的性能问题

时间:2013-10-04 17:29:33

标签: java groovy

我正在尝试使用在Java应用程序中调用的groovy eval(string)方法来追踪性能问题的根源。如果我执行以下代码;

String pattern = "test = ['one','two','three']";
engine.eval(pattern)

它几乎没有时间(0到1毫秒)运行

但是,如果我说以下

String first = "['one','two','three']";
String pattern = "test = " + first; // "identical" String to first approach 
engine.eval(pattern)

运行需要~30 + ms。

更糟糕的是,经过数千次调用后,它将高达60-70ms,尽管我对这一点的关注程度远远低于两次实现之间的时间差异。

关于为什么会发生这种情况的任何解释/关于如何避免这种情况的建议?我怀疑它与Java和/或Groovy编译器有关,我已经开始查看compile()方法,但是我更喜欢它,如果有一种简单的方法可以使现有的代码工作(更少的东西要改变它方式)。

4 个答案:

答案 0 :(得分:2)

如果查看https://github.com/groovy/groovy-core/blob/master/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java?source=cc,您会找到一个用于将字符串映射到类的缓存。问题是ManagedConcurrentMap基本上是一个标识哈希映射,这意味着如果你反复使用相同的字符串,它会很快,因为后续运行会跳过编译。问题版本每次都会创建一个新字符串,因此每次都需要编译它,每次都会生成一个新类。

关于如何避免这种情况:创建基于哈希的缓存

答案 1 :(得分:0)

eval任何一种语言都是出了名的慢,经常被建议远离(" eval是邪恶的")。但是,在你的代码中,字符串连接似乎更多地导致减速,而不是eval本身。

仍然,几毫秒不应该引起关注 - 您是否已确定这会导致代码中出现性能瓶颈?微管理代码可能会导致未来的错误和不清楚的代码,这可能会产生更糟糕的影响。

答案 2 :(得分:0)

您如何衡量调用的时间?如果可能的话,我会测量每个部分(String构建和eval())以确定哪个花费时间,哪个随着迭代次数而增加。因为你说时间随着迭代次数的增加而增加,所以看看垃圾收集。第一种情况使用单个String - 在后一种情况下,每次迭代都要构建一个新的String,因此消耗内存。您可能正在遇到堆限制。

用于查看此内容的一个非常有用的工具是VisualVM。 http://visualvm.java.net/

答案 3 :(得分:0)

最终我们认识到了

eval("['one','two','three']")

完全返回,所以

Object test = engine.eval(first)

相当于

engine.eval("test = " + "['one','two','three']") // see text above for exact syntax
Object test = engine.get("test")

然而它根本没有时间运行。

我仍然很好奇为什么使模式动态对eval()的性能产生如此巨大的影响但是我怀疑需要对Java和/或groovy运行时元素有深刻理解的人才能放弃点亮它。

感谢所有试图提供帮助的人。 的问候,

PS。