Dav*_*les 4 java recursion enums
我已经尝试了3个小时,我无法理解这里发生了什么.
我有一个枚举'迷宫'.出于某种原因,当在此枚举上调用方法"搜索"时,它非常慢(运行3分钟).但是,如果我将相同的方法复制到另一个类作为静态方法,并且我从枚举'Maze'中调用它,它会在一秒钟内运行!
我不明白为什么?Java枚举中的递归方法有什么问题吗?我究竟做错了什么?
public enum Maze
{
A("A.txt"), B("B.txt");
// variables here...
Maze(String fileName)
{
loadMap(fileName);
nodeDistances = new int[nodes.size()][nodes.size()];
setNeighbors();
setDistances();
}
... more methods here ...
private void setDistances()
{
nodeDistances = new int[nodes.size()][nodes.size()];
for (int i = 0; i < nodes.size(); i++) {
setMax(nodeDistances[i]);
// This works!!!
TestMaze.search(nodes, nodeDistances[i], i, 0);
// This DOESN'T WORK
//search(nodes, nodeDistances[i], i, 0);
}
}
public void setMax(int[] a) {
for (int i=0; i<a.length; i++) {
a[i] = Integer.MAX_VALUE;
}
}
public void search(List<Node> allNodes, int[] distances, int curNodeIndex, int curDist)
{
if (curDist < distances[curNodeIndex])
{
distances[curNodeIndex] = curDist;
for (Node n : allNodes.get(curNodeIndex).getNeighbors()) {
search(allNodes, distances, n.getNodeIndex(), curDist + 1);
}
}
}
}
public class TestMaze
{
public static void search(List<Node> allNodes, int[] distances, int curNodeIndex, int curDist)
{
if (curDist < distances[curNodeIndex])
{
distances[curNodeIndex] = curDist;
for (Node n : allNodes.get(curNodeIndex).getNeighbors()) {
search(allNodes, distances, n.getNodeIndex(), curDist + 1);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这种奇怪的行为似乎与JIT有关.似乎是如果它们在类的初始化期间进行JIT编译时方法工作得更慢(即,如果它们经常从static初始化器调用,它也发生在OP的情况下,因为枚举值在初始化期间被实例化).
这是一个小测试:
public class Test {
public static final long N = 40;
static {
long t = System.currentTimeMillis();
computeStatic1(N);
System.out.println("computeStatic1 in initializer: " + (System.currentTimeMillis() - t));
Test x = new Test();
t = System.currentTimeMillis();
x.compute1(N);
System.out.println("compute1 in initializer: " + (System.currentTimeMillis() - t));
computeStatic2(10); // Not enough to launch JIT
x.compute2(10); // Not enough to launch JIT
}
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
computeStatic1(N);
System.out.println("computeStatic1 in main: " + (System.currentTimeMillis() - t));
Test x = new Test();
t = System.currentTimeMillis();
x.compute1(N);
System.out.println("compute1 in main: " + (System.currentTimeMillis() - t));
t = System.currentTimeMillis();
computeStatic2(N);
System.out.println("computeStatic2 in main: " + (System.currentTimeMillis() - t));
t = System.currentTimeMillis();
x.compute2(N);
System.out.println("compute2 in main: " + (System.currentTimeMillis() - t));
}
private long compute1(long n) {
if (n == 0 || n == 1) return 1;
else return compute1(n - 2) + compute1(n - 1);
}
private static long computeStatic1(long n) {
if (n == 0 || n == 1) return 1;
else return computeStatic1(n - 2) + computeStatic1(n - 1);
}
private long compute2(long n) {
if (n == 0 || n == 1) return 1;
else return compute2(n - 2) + compute2(n - 1);
}
private static long computeStatic2(long n) {
if (n == 0 || n == 1) return 1;
else return computeStatic2(n - 2) + computeStatic2(n - 1);
}
}
Run Code Online (Sandbox Code Playgroud)
结果(Sun JVM):
> java Test computeStatic1 in initializer: 4360 compute1 in initializer: 4578 computeStatic1 in main: 4359 compute1 in main: 4610 computeStatic2 in main: 2859 compute2 in main: 2859
JIT禁用:
> java -Xint Test computeStatic1 in initializer: 20578 compute1 in initializer: 21656 computeStatic1 in main: 20250 compute1 in main: 21391 computeStatic2 in main: 20250 compute2 in main: 21375
在IBM J9 VM中,仅对static方法观察到此行为:
$ java Test computeStatic1 in initializer: 5053 compute1 in initializer: 2488 computeStatic1 in main: 5044 compute1 in main: 2473 computeStatic2 in main: 2597 compute2 in main: 2489