我正在用Java编写一些专用数据结构,用于浏览器(用GWT编译成JavaScript)。
我正在尝试匹配一些内置JDK类的性能我注意到运行速度相当快,但当我将我的代码跟踪与一些模拟的JDK代码进行比较时,我有很多调用dynamicCast和canCastUnsafe,而JDK模拟类则没有。它只是解释了性能上的差异......
那里的任何GWT大师都知道如何避免这种情况?这相当于20%的开销: - (
详细说明:
以下是10,000个随机整数插入的配置文件输出(在Firebug中捕获),介于0到100,000之间,分为两个不同的数据结构:
Google的java.util.TreeMap(红黑树)的TreeMap实现:
Profile (4058.602ms, 687545 calls)
Function Calls Percent Own Time
$insert_1 129809 41.87% 1699.367ms
$compare_0 120290 16% 649.209ms
$isRed 231166 13.33% 540.838ms
compareTo_0 120290 8.96% 363.531ms
$put_2 10000 6.02% 244.493ms
wrapArray 10000 3.46% 140.478ms
createFromSeed 10000 2.91% 118.038ms
$TreeMap$Node 10000 2.38% 96.706ms
initDim 10000 1.92% 77.735ms
initValues 10000 1.49% 60.319ms
$rotateSingle 5990 0.73% 29.55ms
TreeMap$Node 10000 0.47% 18.92ms
我的代码(AVL树):
Profile (5397.686ms, 898603 calls)
Function Calls Percent Own Time
$insert 120899 25.06% 1352.827ms
$compare 120899 17.94% 968.17ms
dynamicCast 120899 14.12% 762.307ms <--------
$balanceTree 120418 13.64% 736.096ms
$setHeight 126764 8.93% 482.018ms
compareTo_0 120899 7.76% 418.716ms
canCastUnsafe 120899 6.99% 377.518ms <--------
$put 10000 2.59% 139.936ms
$AVLTreeMap$Node 9519 1.04% 56.403ms
$moveLeft 2367 0.36% 19.602ms
AVLTreeMap$State 9999 0.36% 19.429ms
$moveRight 2378 0.34% 18.295ms
AVLTreeMap$Node 9519 0.34% 18.252ms
$swingRight 1605 0.26% 14.261ms
$swingLeft 1539 0.26% 13.856ms
补充意见:
在比较功能中应用了dynamicCast:
cmp = dynamicCast(right.key,4).compareTo $(key);
如果类没有实现Map,那么dynamicCast就会消失(即:只是从类中删除“implements Map”。无论是通过接口还是直接访问它都无关紧要。这导致同一行编译为:
cmp = right.key.compareTo $(key);
这是来自SkipList的Java源代码的相关部分:
private int compare(Node a, Object o) {
if (comparator != null)
return comparator.compare((K) a.key, (K) o);
return ((Comparable<K>) a.key).compareTo((K) o);
}
public V get(Object k) {
K key = (K) k;
Node<K, V> current = head;
for (int i = head.height - 1; i >= 0; i--) {
Node<K, V> right;
while ((right = current.right[i]) != null) {
int cmp = compare(right, key);
...
}
}
}
答案 0 :(得分:4)
不幸的是,我仍然不清楚原因,但根据我的经验,它似乎来自明确的演员,如:
((Comparable) obj).compareTo(other)
生成的Javascript看起来像:
dynamicCast(obj, 1).compareTo(other);
其中1是生成的typeId,表示强制转换的目标。 dynamicCast依次调用canCastUnsafe,如果为false,则抛出ClassCastException。该值的值为debated,因为这已经在托管模式中捕获。
可以回避JSNI:
public static native int compare(Object a, Object b) /*-{
return a.@java.lang.Comparable::compareTo(Ljava/lang/Object;)(b);
}-*/;
答案 1 :(得分:1)
Dunno如果你在GWT贡献者的论坛中看过this thread ......
基本上,它从您已经识别的相同问题开始,提出了一些新的编译器标志,然后继续展示如何使用一些JSNI来绕过转换。
编辑在GWT主干中有一个新的编译器标志。见the wiki ...
答案 2 :(得分:1)
GWT 2.1及更高版本的更新答案:
自GWT 2.1(至少是第一次提到)以来,GWT编译器有一个名为-XdisableCastChecking
的新编译器参数,它禁用所有运行时的运行时检查。
注意,此选项标记为实验性(可能因为这会使类转换异常很难调试)。
在我的应用程序中dynamicCast
在简短的配置文件中被调用了数千次,并且是Firebug探查器中第3个最耗时的方法。使用此编译器参数可显着减少Chrome Speed Tracer中“长时间事件”消息的数量。
有关此参数和其他编译器参数,请参阅GWT Compiler Options。
答案 3 :(得分:0)
这绝对是一个编译器问题:我遇到了以下问题:
final DefaultIconedSuggestBox<SuggestValueProxy, IconedValueHolderItem<SuggestValueProxy>> fieldValueWidget = getCategoryWidget().getFieldValueWidget();
我真的不知道如何解决它:这一行发生在我从一个模块转换到另一个模块的时候(它可能与代码分割器问题有关:即使我没有使用代码拆分:我只是用另一个模块加载另一个页面)
答案 4 :(得分:-1)
使用java 1.5泛型和通配符是否可以避免这种情况?