我正在用 Java 编写一些用于浏览器的特殊用途数据结构(使用 GWT 编译为 JavaScript)。

我正在尝试匹配一些内置 JDK 类的性能我注意到运行速度相当快,但是当我将我的代码跟踪与一些模拟的 JDK 代码进行比较时,我有很多对 dynamicCast 和 canCastUnsafe 的调用,而 JDK 模拟的类没有。它也只是解释了性能的差异......

那里有任何 GWT 大师知道如何避免这种情况吗?这相当于 20% 的开销:-(

细节:

这是将 0 到 100,000 之间的 10,000 次随机整数插入两种不同数据结构的配置文件输出(在 Firebug 中捕获):

谷歌的 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 

其他意见:
  • 我制作的另一个数据结构(SkipList)也存在同样的问题。
  • 在比较函数中应用了 dynamicCast:

    cmp = dynamicCast(right.key, 4).compareTo$(key);
  • 如果类没有实现 Map,dynamicCast 就会消失(即:只是从类中删除“implements Map”。无论是通过接口(interface)还是直接访问它都没有关系。这会导致同一行编译为:

    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); 
     
                ... 
            } 
        } 
    } 
    

    请您参考如下方法:

    不幸的是,我仍然不清楚原因,但根据我的经验,它似乎来自明确的 Actor ,例如:

    ((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);  
    }-*/; 
    


    评论关闭
    IT干货网

    微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!