簡體   English   中英

違反一個空的lambda比檢查一個潛在的null lambda更好還是更差?

[英]Is defaulting to an empty lambda better or worse than checking for a potentially null lambda?

我正在研究Java 8中的小型場景圖實現。基本場景節點看起來像這樣:

public class SceneNode {
  private final List<SceneNode> children = new ArrayList<>();
  protected Runnable preRender;
  protected Runnable postRender;
  protected Runnable render;

  public final void render() {
    preRender.run();
    render.run();
    for (Renderable child : children) {
      child.render();
    }
    postRender.run();
  }
}

如果Runnables默認為() -> {}這可以正常工作。 但是,或者我可以允許它們為null,但這意味着render()方法必須如下所示:

  public final void render() {
    if (null != preRender) { preRender.run(); }
    if (null != render) { render.run(); }
    for (Renderable child : children) {
      child.render();
    }
    if (null != postRender) { postRender.run(); }
  }

所以我的問題是,null檢查引入的分支的隱式成本是否可能比JVM最終編譯空lambda的成本更高或更低? 看起來它應該花費更多來檢查null,因為潛在的分支限制了優化,而可能是Java編譯器或JVM應該足夠聰明以將空lambda編譯成no-op。

有趣的 ,當使用-client參數運行JVM時, 檢查null似乎比調用空lambda或空匿名類快一點 使用-server運行時,所有方法的性能都相同。

我用Caliper做了一個微基准測試。

這是測試類(編譯時需要的最新Caliper表單git):

@VmOptions("-client")
public class EmptyLambdaTest {

    public Runnable emptyLambda = () -> {};
    public Runnable emptyAnonymousType = new Runnable() {
        @Override
        public void run() {}
    };

    public Runnable nullAbleRunnable;

    @Benchmark
    public int timeEmptyLambda(int reps){
        int dummy = 0;
        for (int i = 0; i < reps; i++) {
            emptyLambda.run();
            dummy |= i;
        }
        return dummy;
    }

    @Benchmark
    public int timeEmptyAnonymousType(int reps){
        int dummy = 0;
        for (int i = 0; i < reps; i++) {
            emptyAnonymousType.run();
            dummy |= i;
        }
        return dummy;
    }

    @Benchmark
    public int timeNullCheck(int reps){
        int dummy = 0;
        for (int i = 0; i < reps; i++) {
            if (nullAbleRunnable != null) {
                nullAbleRunnable.run();
            }
            dummy |= i;
        }
        return dummy;
    }

}

以下是基准測試結果:

違反一個空的lambda比檢查一個潛在的null lambda更好還是更差?

這與詢問是否更好地測試null String參數或嘗試替換空String一樣基本相同。

答案是,這取決於您是否要將 null視為編程錯誤......或者不是。

我個人認為, 意外的 null應該被視為編程錯誤,並且你應該允許程序與NPE崩潰。 這樣,問題就會提前引起你的注意,並且更容易追蹤和修復......而不是你用一些“做好”的價值來阻止NPE被拋出。

但是,當然,這不適用於預期的 null值; 即,當API javadocs說null是允許值時,並說出它意味着什么。


這也與您設計 API的方式有關。 在這種情況下,問題是你的API規范(即javadoc!)是否應該堅持程序員提供no-op lambda,或者將null視為同一個東西。 歸結為以下兩者之間的妥協:

  • API客戶方便,
  • API實現工作,和
  • 魯棒性; 例如,當使用錯誤初始化變量的值時......

我更關心使用空lambda與使用null並且必須進行空檢查的運行時性能的含義。

我的直覺是測試null會更快,但性能上的任何差異都會很小,並且很可能它對應用程序的整體性能不會很重要

(UPDATE -原來,我的直覺是根據@巴爾德的微標桿“說對了一半”對於一個。 -client模式JVM,空檢查是有點快,但還不足以描述有關對於一個。 -server模式JVM中, JIT編譯器顯然將兩種情況都優化為具有相同性能的本機代碼。)

我建議你認為你會(或至少應該 )處理任何潛在的優化問題:

  1. 推遲任何優化,直到您的應用程序正常運行。
  2. 對應用程序進行基准測試,看它是否已經足夠快
  3. 分析應用程序以查看真正的熱點所在
  4. 開發並測試推定的優化
  5. 重新運行基准測試,看看它是否有所改進
  6. 轉到第2步。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM