C#でtry/finallyのオーバーヘッド?
質問
私たちは、いつ、なぜ
try
/
catch
そして
try
/
catch
/
finally
. という使用例があることも知っています。
try
/
finally
(という方法です(特に
using
文が実装されているからです)。
に関する質問も見受けられます。 try/catchと例外のオーバーヘッド .
しかし、私がリンクした質問では、JUST try-finallyを持つことのオーバーヘッドについては語られていません。
の中で起こるいかなるものからも例外が発生しないと仮定すると、そのような例外が発生する可能性はありません。
try
ブロックの中で何が起きても例外は発生しないと仮定すると
finally
ステートメントが
try
ブロックから離れるときに実行されるのでしょうか?
もう一度言いますが、私が質問しているのはあくまでも
try
/
finally
いいえ
catch
例外のスローはありません。
ありがとうございます!
EDITです。 さて、私の使用例をもう少しうまく示すことにします。
どちらを使うべきでしょうか。
DoWithTryFinally
それとも
DoWithoutTryFinally
?
public bool DoWithTryFinally()
{
this.IsBusy = true;
try
{
if (DoLongCheckThatWillNotThrowException())
{
this.DebugLogSuccess();
return true;
}
else
{
this.ErrorLogFailure();
return false;
}
}
finally
{
this.IsBusy = false;
}
}
public bool DoWithoutTryFinally()
{
this.IsBusy = true;
if (DoLongCheckThatWillNotThrowException())
{
this.DebugLogSuccess();
this.IsBusy = false;
return true;
}
else
{
this.ErrorLogFailure();
this.IsBusy = false;
return false;
}
}
このケースは戻りポイントが2つしかないので単純化しすぎですが、もし4つ...10つ...100つあったらと想像してみてください。
ある時点で、私は
try
/
finally
は、以下の理由からです。
- DRY の原則を守る (特に出口が多くなるにつれて)
-
もし内部関数が例外を投げないことについて私が間違っていることがわかったら、その時は
this.Working
に設定されていることを確認します。false
.
では、仮に、与えられた
パフォーマンスへの懸念、保守性、および DRY 原則があります。
の場合、どのような数の出口ポイントに対して(特に私が
ができる
に関連するパフォーマンス・ペナルティを引き受けたいですか?
try
/
finally
?
EDIT #2です。
の名前を変更しました。
this.Working
を
this.IsBusy
. すみません、これはマルチスレッドであることを言及するのを忘れていました(しかし、実際にメソッドを呼び出すのは1つのスレッドだけです)。他のスレッドはオブジェクトが仕事をしているかどうかを確認するためにポーリングしています。
どのように解決するのですか?
実際に得られるものを見てみませんか?
ここにC#の簡単なコードの塊があります。
static void Main(string[] args)
{
int i = 0;
try
{
i = 1;
Console.WriteLine(i);
return;
}
finally
{
Console.WriteLine("finally.");
}
}
そして、デバッグビルドでの結果のILは以下の通りです。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init ([0] int32 i)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: nop
L_0004: ldc.i4.1
L_0005: stloc.0
L_0006: ldloc.0 // here's the WriteLine of i
L_0007: call void [mscorlib]System.Console::WriteLine(int32)
L_000c: nop
L_000d: leave.s L_001d // this is the flavor of branch that triggers finally
L_000f: nop
L_0010: ldstr "finally."
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: nop
L_001b: nop
L_001c: endfinally
L_001d: nop
L_001e: ret
.try L_0003 to L_000f finally handler L_000f to L_001d
}
で、これがデバッグ時にJITで生成されたアセンブリです。
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00288D34h],0
00000028 je 0000002F
0000002a call 59439E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
try
{
0000003a nop
i = 1;
0000003b mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000042 mov ecx,dword ptr [ebp-40h]
00000045 call 58DB2EA0
0000004a nop
return;
0000004b nop
0000004c mov dword ptr [ebp-20h],0
00000053 mov dword ptr [ebp-1Ch],0FCh
0000005a push 4E1584h
0000005f jmp 00000061
}
finally
{
00000061 nop
Console.WriteLine("finally.");
00000062 mov ecx,dword ptr ds:[036E2088h]
00000068 call 58DB2DB4
0000006d nop
}
0000006e nop
0000006f pop eax
00000070 jmp eax
00000072 nop
}
00000073 nop
00000074 lea esp,[ebp-0Ch]
00000077 pop ebx
00000078 pop esi
00000079 pop edi
0000007a pop ebp
0000007b ret
0000007c mov dword ptr [ebp-1Ch],0
00000083 jmp 00000072
さて、tryとfinallyとreturnをコメントアウトすると、JITからほぼ同じアセンブリが得られます。 違いはfinallyブロックへのジャンプと、finallyが実行された後にどこに行くかを決定するコードです。 つまり、ほんのわずかな違いです。 中括弧はnop命令なので、次の命令へのジャンプになり、これもnopになります。 pop eax とその後の jmp eax も同様に安価です。
{
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00198D34h],0
00000028 je 0000002F
0000002a call 59549E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
//try
//{
i = 1;
0000003a mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000041 mov ecx,dword ptr [ebp-40h]
00000044 call 58EC2EA0
00000049 nop
// return;
//}
//finally
//{
Console.WriteLine("finally.");
0000004a mov ecx,dword ptr ds:[034C2088h]
00000050 call 58EC2DB4
00000055 nop
//}
}
00000056 nop
00000057 lea esp,[ebp-0Ch]
0000005a pop ebx
0000005b pop esi
0000005c pop edi
0000005d pop ebp
0000005e ret
つまり、try/finallyにかかるコストはとてもとても小さいということです。 これが問題になるような問題領域はほとんどありません。 memcpy のようなものを使用していて、コピーされる各バイトに try/finally を置き、何百 MB ものデータのコピーを続行する場合、それが問題になることはわかりますが、ほとんどの使用法では? しかし、ほとんどの場合、それは無視できます。
関連
-
[解決済み】GDI+、JPEG画像をMemoryStreamに変換する際にジェネリックエラーが発生しました。
-
[解決済み】C#におけるtypedefの等価性
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] Try-catchは私のコードをスピードアップさせるか?
-
[解決済み] Javaにおける例外処理によるパフォーマンスへの影響とは?
-
[解決済み] なぜPythonでは "finally "節が必要なのでしょうか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】 Try-finallyブロックがStackOverflowErrorを防ぐ
-
[解決済み】空のtryブロックでtry {} finally {}を使用するのはなぜですか?
-
[解決済み】try {...} finally {...} は良くて、try {...} catch{} はダメなのはなぜ?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】WebForms UnobtrusiveValidationModeは、jqueryのScriptResourceMappingを必要とする
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】非静的メソッドはターゲットを必要とする
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み] 2つのリストを結合する
-
[解決済み] [Solved] .NETでスレッドの終了を待つには?
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。
-
[解決済み] C#のtry/catchの本当のオーバーヘッドは何ですか?