試しに最終的に高価です


14

関数を終了する前にリソースのクリーンアップを行う必要があるコードの場合、これらの2つの方法の間に大きなパフォーマンスの違いがあります。

  1. すべてのreturnステートメントの前にリソースをクリーニングする

    void func()
    {
        login();
    
        bool ret = dosomething();
        if(ret == false)
        {
            logout();
            return;
        }
    
        ret = dosomethingelse();
        if(ret == false)
        {
            logout();
            return;
        }
    
        dootherstuff();
    
        logout();
    }
  2. finallyブロックでのリソースのクリーニング

    void func()
    {
        login();
    
        try
        {
            bool ret = dosomething();
            if(ret == false)
                return;
    
            ret = dosomethingelse();
            if(ret == false)
                return;
    
            dootherstuff();
    
        }
        finally
        {
            logout();
        }
    }

サンプルプログラムでいくつかの基本的なテストを行いましたが、大きな違いはないようです。私はこれfinallyを行う方法を非常に好みますが、大きなプロジェクトでパフォーマンスが低下するのではないかと考えていました。


3
回答として投稿する価値はありませんが、ありません。Javaを使用している場合、例外がデフォルトのエラー処理戦略であると予想される場合は、try / catch / finallyを使用する必要があります-言語は使用しているパターンに最適化されています。
ジョナサンリッチ

1
@ジョナサンリッチ:どのように?
ヘイレム

2
あなたが達成しようとしていることを表現するような方法でコードをきれいに書いてください。問題があることがわかったら後で最適化してください。最初は遅くないものを数ミリ秒削る可能性があると思うので、言語機能を避けないでください。
ショーンマクサムシング

@mikeTheLiar-あなたが私が書くべきだと言うならif(!cond)、それが私にこれをさせたのはjavaです。C ++では、ブール値と他の型の両方のコードを記述する方法int x; if(!x)です。Javaでこれを使用できるのはのみであるためbooleans、Javaでif(cond)&の使用を完全に停止しましたif(!cond)
user93353

1
@ user93353それは私を悲しくさせます。(someIntValue != 0)ブール値を評価するのではなく、比較するよりもむしろ見たいです。それは私にとって臭いであり、野生でそれを見るとすぐにそれをリファクタリングします。
MikeTheLiar

回答:


23

Javaの例外どれくらい遅いかで示されているように?の遅さはtry {} catch {}例外自体の表明内にあることがわかります。

例外を作成すると、ランタイムからコールスタック全体がフェッチされます。これは、費用がかかる場所です。例外を作成していない場合、これはごくわずかな時間の増加にすぎません。

この質問で与えられた例では、例外はありません。例外を作成しても速度が低下することはないでしょう-作成されません。代わりに、try {} finally {}finallyブロック内でリソースの割り当て解除を処理します。

したがって、質問に答えるために、いいえ、try {} finally {}例外を使用しない構造内に実際のランタイム費用はありません(見られるように、前代未聞ではありません)。何である 1は、コードを読み取り、この典型的ではないコードのスタイルを見て、コーダは何か他のものは後に、この方法で起こることを周りに彼らの心を取得しなければならないとき、おそらく高価なことは、メンテナンス時間がreturn以前の呼び出しに戻る前に。


前述のように、メンテナンスはこれを行う両方の方法の引数です。記録については、検討後、私の好みは最終的なアプローチになります。

誰かに新しい言語構造を教えるメンテナンス時間を考慮してください。見るtry {} finally {}ことはJavaコードでよく目にするものではないため、人々を混乱させる可能性があります。人々が見慣れているよりも、Javaで少し高度な構造を学習するためのある程度のメンテナンス時間があります。

finally {}ブロックは必ず実行されます。そして、これがあなたがそれを使うべき理由です。また、誰かが適切なタイミングでログアウトを含めるのを忘れたり、不適切なタイミングでログアウトを呼び出したり、呼び出した後に復帰/終了を忘れて2回呼び出される場合、非最終アプローチのデバッグのメンテナンス時間も考慮してください。これには非常に多くのバグが存在する可能性があるため、使用try {} finally {}すると不可能になります。

これらの2つのコストを比較検討する場合、このアプローチを使用しないと、メンテナンスに時間がかかりtry {} finally {}ます。try {} finally {}ブロックが他のバージョンと比較されるミリ秒の小数または追加のjvm命令の数について悩むことができますが、リソースの割り当て解除に対処する理想的ではない方法のデバッグに費やされる時間も考慮する必要があります。

保守可能なコードを最初に、できればバグが後で記述されないように記述してください。


1
提案されていない編集はこう言いました:「実行時例外に関して他の方法では得られない保証を試用/最終的に提供します。好むと好まざるとにかかわらず、どの行も事実上例外を投げることができます」 。質問で与えられた構造には、コードのパフォーマンスを低下させる追加の例外はありません。非試行/最終ブロックと比較して、ブロックの周りに試行/最終をラップすることによる追加のパフォーマンスへの影響はありません。

2
try-finallyのこの使用法を理解するよりもメンテナンスがさらに高価になる可能性があるのは、いくつかのクリーンアップブロックをメンテナンスする必要があることです。少なくとも、追加のクリーンアップが必要な場合、それを配置する場所は1つしかないことを知っています。
バートヴァンインゲンシェナウ

@BartvanIngenSchenau確かに。try-finallyはおそらくそれを処理するための最良の方法です。コードで見た構造のように一般的ではありません。一般的に、try catchと例外処理を理解しようとするのに十分な問題があります。 -最後にキャッチなし?何?人々は本当に理解していません。あなたが提案したように、言語構造を理解し、それを避けて物事を粗末にしようとするよりも良いです。

私は主に、try-finallyの代替手段も無料ではないことを伝えたかったのです。費用についての追加の追加投票をお願いしたい。
バートヴァンインゲンシェナウ

5

/programming/299068/how-slow-are-java-exceptions

この質問に対する受け入れられた回答は、try catchブロックで関数呼び出しをラップすることは、裸の関数呼び出しよりも5%少ないコストであることを示しています。実際に例外をスローしてキャッチすると、ランタイムは、裸の関数呼び出しの66倍以上に膨れ上がりました。したがって、例外設計が定期的にスローされることを期待する場合は、適切にプロファイルされたパフォーマンスクリティカルコードでそれを回避しようとしますが、例外的な状況がまれである場合、それは大したことではありません。


3
「例外的な状況がまれな場合」 -まあそこにトートロジーがあります。例外とはまれなことを意味し、それがまさに例外の使用方法です。設計または制御フローの一部であってはなりません。
ジェシーC.スライサー

1
例外は実際には必ずしも珍しいことではなく、単なる偶発的な副作用です。たとえば、あなたが悪いUIの人々は例外ユースケースは、通常の流れよりも頻繁に流れる可能性があります持っている場合
Esailija

2
質問のコードに例外がスローされることはありません。

2
@ JesseC.Slicerフロー制御として使用されるのを見るのが珍しくない言語があります。一例として、Pythonで何かを反復する場合、イテレーターは終了時にストップイテレーション例外をスローします。また、OCamlでは、標準ライブラリは非常に「スローハッピー」であるように見え、まれではない状況が多数発生します(マップがあり、スローするマップに存在しないものを検索しようとすると)。
ストーンメタル

@stonemetalとしてはKeyError例外で、Pythonの辞書を行い
Izkata

4

最適化の代わりに-コードが何をしているか考えてください。

finallyブロックの追加は別の実装です。つまり、すべての例外でログアウトします。

特に、ログインが例外をスローした場合、2番目の関数の動作は最初の関数とは異なります。

ログインとログアウトが実際に関数の動作の一部ではない場合、メソッドは1つのことと1つのことをうまく行うことをお勧めします。

    void func()
    {
            bool ret = dosomething();
            if(ret == false)
                return;

            ret = dosomethingelse();
            if(ret == false)
                return;

            dootherstuff();

    }

また、ログイン/ログアウトを管理するコンテキストにすでにカプセル化されている関数に含める必要があります。これらは、メインコードの実行内容とは根本的に異なるように見えるためです。

あなたの投稿はJavaとしてタグ付けされていますが、私はあまり慣れていませんが、.netではこれにusingブロックを使用します:

すなわち:

    using(var loginContext = CreateLoginContext()) 
    {
            // Do all your stuff
    }

また、ログインコンテキストには、リソースをログアウトしてクリーンアップするDisposeメソッドがあります。

編集:私は実際に質問に答えませんでした!

測定可能な証拠はありませんが、これがこれ以上高価になるとは期待していません。

質問には答えていませんが、OPには役立つと思うので、残りの回答は残しておきます。


1
答えを完成させるために、Java 7では、using問題のリソースがAutoCloseableインターフェースを実装していると仮定して、.net 構造に似たtry-with-resourcesステートメントを導入しました。
ヘイレム

このret変数も削除します。この変数は、1行後にチェックするために2回だけ割り当てられます。それを作りますif (dosomething() == false) return;
-ott--

同意しましたが、OPコードは提供されたままにしたかったのです。
マイケル

@ ott-- OPのコードはユースケースの単純化であると仮定します-たとえば、もっと似たようなものがあるかもしれませんがret2 = doSomethingElse(ret1)、それは質問に関係ないので削除されました。
イズカタ

if (dosomething() == false) ...悪いコードです。もっとintiutive使用if (!dosomething()) ...
ステファン・ハイル

1

前提:C#コードで開発している。

簡単な答えは、try / finallyブロックを使用してもパフォーマンスに大きな影響はありません。例外をスローしてキャッチすると、パフォーマンスが低下します。

より長い答えは、自分の目で確かめることです。生成された基礎となるCILコード(たとえば、赤ゲートリフレクター)を見ると、基礎となるCIL命令が生成され、その影響を確認できます。


11
質問にはjavaというタグが付けられています。
ヨアヒムザウアー

よく見つけました!;)
マイケルショー

3
また、メソッドは大文字ではありませんが、それは良い味になります。
エリックReppen

質問がc#であった場合はまだ良い答えです:)
PhillyNJ

-2

他の人がすでに指摘したように、Tteseコードは、どちらかdosomethingelseまたはdootherstuff例外をスローすると、異なる結果になります。

そして、はい、少なくともすべての関数呼び出しは例外をスローできStackOVerflowErrorます!これらを正しく処理することはまれですが(呼び出されたクリーンアップ関数にはおそらく同じ問題があるため、場合によっては(たとえばロックの実装など)、正しく処理することも重要です...


2
これは前に6件の回答に比べて大幅のオファーは何もしていないようだ
ブヨ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.