代码之家  ›  专栏  ›  技术社区  ›  itsadok

GWT:如何避免在生成的JavaScript代码中调用dynamicCast和CancastSafe?

gwt
  •  7
  • itsadok  · 技术社区  · 17 年前

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

    我试图匹配一些内置JDK类的性能,我注意到它们运行得相当快,但是当我将我的代码跟踪与一些模拟JDK代码进行比较时,我的代码跟踪有很多对dynamicCast和CancastSafe的调用,而JDK模拟类则没有。这也正是性能差异的原因。。。

    有没有GWT大师知道如何避免这种情况?这相当于20%的管理费用:-(

    细节:

    以下是10000个随机整数插入到两个不同数据结构中的配置文件输出(在Firebug中捕获):

    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
    

    其他意见:

    • 我制作的另一个数据结构(SkipList)也存在同样的问题。
    • cmp=dynamicCast(right.key,4)。与$(key)比较;

    • 如果类未实现映射(即:仅从类中删除“implements Map”),则dynamicCast将消失。无论是通过接口访问还是直接访问dynamicCast。这将导致同一行编译为:

      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);
    
                ...
            }
        }
    }
    
    5 回复  |  直到 17 年前
        1
  •  4
  •   itsadok    17 年前

    不幸的是,我仍然不太清楚原因,但根据我的经验,这似乎来自于明确的演员阵容,比如:

    ((Comparable) obj).compareTo(other)
    

    dynamicCast(obj, 1).compareTo(other);
    

    其中1是生成的typeId,表示强制转换的目标。dynamicCast反过来调用CancastSafetable,如果为false,则抛出ClassCastException。这一点的价值已经得到了肯定 debated ,因为这将在托管模式下被捕获。

    使用JSNI可以避开它:

    public static native int compare(Object a, Object b) /*-{
        return a.@java.lang.Comparable::compareTo(Ljava/lang/Object;)(b); 
    }-*/;
    
        2
  •  1
  •   jgindin    17 年前

    不知道你是否见过 this thread 在GWT贡献者论坛中。。。

    基本上,它从您识别的相同问题开始,提出了一些新的编译器标志,并继续展示如何使用一些JSNI绕过强制转换。

    编辑 the wiki ...

        3
  •  1
  •   Stein G. Strindhaug    15 年前

    GWT 2.1版及更高版本的更新答案:

    自从GWT2.1(至少这是第一次提到)以来,GWT编译器有一个新的编译器参数,名为 -XdisableCastChecking 这将禁用强制转换的所有运行时检查。 注意,这个选项被标记为实验性的(可能是因为这会使类强制转换异常很难调试)。

    在我的应用程序中 dynamicCast 在一个简短的概要文件运行中被调用了数千次,是Firebug概要文件中第三个最耗时的方法。使用此编译器参数可显著减少Chrome Speed Tracer中“长持续时间事件”消息的数量。

    看见 GWT Compiler Options 用于此编译器参数和其他编译器参数。

        4
  •  0
  •   Zied Hamdi    12 年前

    这肯定是编译器的问题:我在下面一行遇到了问题:

    final DefaultIconedSuggestBox<SuggestValueProxy, IconedValueHolderItem<SuggestValueProxy>> fieldValueWidget = getCategoryWidget().getFieldValueWidget();
    

        5
  •  -1
  •   François Wauquier    17 年前

    推荐文章