有效地将 Clojure 函数传递给 java
Pass Clojure functions to java efficiently
我想在 Java 中使用 Java 循环实现一个朴素的非惰性 map
。
我主要关心的是 Clojure java 中的函数调用。
这是我的代码:
A class 调用 NaiveClojure 使用 Java
实现功能
package java_utils;
import java_utils.ApplyFn;
public class NaiveClojure {
public static Object[] map (ApplyFn applyfn, Object function, Object[] coll) {
int len = coll.length;
for (int i = 0 ; i < len ; i++) {
coll[i] = applyfn.apply(function, coll[i]);
}
return coll;
}
}
名为 ApplyFn 的摘要 class
package java_utils;
public abstract class ApplyFn {
public abstract Object apply (Object function, Object value);
}
所以在 Clojure 中我有
(defn java-map [f coll]
(let [java-fn (proxy [ApplyFn] []
(apply [f x]
(f x)))]
(seq (NaiveClojure/map java-fn f (to-array coll)))))
我试过了
(doall (map inc (range 0 10000))) ;; 3.4 seconds for 10000 operations
(java-map inc (range 0 10000) ;; 5.4 seconds
我的意思不是要超越map
(我是作为例子实现的),我只是想用特定的功能做那样的事情(而不是重新发明Clojure的轮子)。
有没有更好的方法来传递这样的函数? (作为一种简单快捷的方式)
为了总体上改进我的编码(我的理论知识很差),你知道这里的 perf 是什么吗?
我会说像 Object 这样的一般类型,但我没有看到其他任何东西
谢谢
你不用担心,你的做法很好,也很高效。
coll[i] = applyfn.apply(function, coll[i]);
这是一种非常正常的处理方式。当测量它时,请记住,正如 Valentin Waeselynck 指出的那样,记住使用可靠的微基准测试功能,还要记住,单独对这种小代码块进行基准测试是很棘手的。
当您生成一个 clojure 函数时,它会生成一个 "normal" java class,并带有一个名为 apply 的方法。调用起来不会慢,因为您正在调用一个最初用 Clojure 编写的函数,而不是在 class 上调用一个用普通 Java 语法编写的方法。一旦 Hotspot JIT 完成预热和内联,它可能会像没有方法调用一样快(这就是为什么对这种事情进行基准测试比直觉上应该更难)。
我想在 Java 中使用 Java 循环实现一个朴素的非惰性 map
。
我主要关心的是 Clojure java 中的函数调用。
这是我的代码:
A class 调用 NaiveClojure 使用 Java
实现功能package java_utils;
import java_utils.ApplyFn;
public class NaiveClojure {
public static Object[] map (ApplyFn applyfn, Object function, Object[] coll) {
int len = coll.length;
for (int i = 0 ; i < len ; i++) {
coll[i] = applyfn.apply(function, coll[i]);
}
return coll;
}
}
名为 ApplyFn 的摘要 class
package java_utils;
public abstract class ApplyFn {
public abstract Object apply (Object function, Object value);
}
所以在 Clojure 中我有
(defn java-map [f coll]
(let [java-fn (proxy [ApplyFn] []
(apply [f x]
(f x)))]
(seq (NaiveClojure/map java-fn f (to-array coll)))))
我试过了
(doall (map inc (range 0 10000))) ;; 3.4 seconds for 10000 operations
(java-map inc (range 0 10000) ;; 5.4 seconds
我的意思不是要超越map
(我是作为例子实现的),我只是想用特定的功能做那样的事情(而不是重新发明Clojure的轮子)。
有没有更好的方法来传递这样的函数? (作为一种简单快捷的方式) 为了总体上改进我的编码(我的理论知识很差),你知道这里的 perf 是什么吗? 我会说像 Object 这样的一般类型,但我没有看到其他任何东西
谢谢
你不用担心,你的做法很好,也很高效。
coll[i] = applyfn.apply(function, coll[i]);
这是一种非常正常的处理方式。当测量它时,请记住,正如 Valentin Waeselynck 指出的那样,记住使用可靠的微基准测试功能,还要记住,单独对这种小代码块进行基准测试是很棘手的。
当您生成一个 clojure 函数时,它会生成一个 "normal" java class,并带有一个名为 apply 的方法。调用起来不会慢,因为您正在调用一个最初用 Clojure 编写的函数,而不是在 class 上调用一个用普通 Java 语法编写的方法。一旦 Hotspot JIT 完成预热和内联,它可能会像没有方法调用一样快(这就是为什么对这种事情进行基准测试比直觉上应该更难)。