次のコードのうち、オブジェクトxを変換するための最速/ベストプラクティスはどれですか?
int myInt = (int)x;
または
int myInt = Convert.ToInt32(x);
または
int myInt = Int32.Parse(x);
または文字列「s」の場合
int myInt;
Int32.TryParse(s, out myInt);
Intだけでなく、Convertにメソッドがあるデータ型に対して、どれが最も高速に実行されるのか知りたいです。例としてintを使用しました。
編集:このケースは、データテーブルから情報を取得することから発生しました。 (int)はまだ最速で動作しますか?
いくつかのテストから、オブジェクトx = 123123123の場合、多くの人が言っているように、intが最も高速に実行されます。 xが文字列の場合、Parseは最も速く実行されます(注:キャストは例外をスローします)。私が本当に気になるのは、値が次の方法で取得されているときにそれらがどのように実行されるかです。
foreach(DataRow row in someTable.Rows)
{
myInt = (int)row["some int value"];
myInt2 = Int.Parse(row["some int value"]);
myInt2 = Convert.ToInt32(row["some int value"]);
}
数千回試してみませんか?
(これはすべての「最速:」の質問に当てはまります)
うーん、何年にもわたって多くの反対投票があった...私はこの答えについてさらに詳しく説明するべきだと思う。
上記の声明は、私の青春期にある程度の軽薄さをもって行われましたが、私はまだその感情に同意します。 SO質問を作成する時間を費やして、それぞれ1ミリ秒未満かかる2つまたは3つの操作のうち、何が速いかを他の人に尋ねるのは価値がありません。
1つが他のサイクルよりも1〜2サイクルかかる可能性があるという事実は、日常の使用ではほとんど間違いなく無視できます。そして、何百万ものオブジェクトをintに変換しているときに、アプリケーションのパフォーマンスの問題に気付いた場合は、that'sactualコードを使用すると、int変換が実際にボトルネックになっているかどうかを簡単にテストできます。
そして、今日はobject-intコンバーターですが、明日は、object-DateTimeコンバーターに長い時間がかかると思うかもしれません。最速の方法を見つけるために、別のSO質問を作成しますか?
あなたの状況(今までに解決されてから間違いなく)については、コメントで述べたように、データベースにクエリを実行しているので、object-int変換の心配はほとんどありません。私があなただったら、あなたが言った変換方法のどれかを使うでしょう。問題が発生した場合は、プロファイラーまたはロギングを使用して、呼び出しを分離します。次に、object-int変換が100万回実行されており、その変換にかかった合計時間が比較的長く感じられる場合は、別の変換方法を使用してプロファイルを変更します。最短時間の変換方法を選択してください。これを別のソリューション、またはLINQPad、Powershellなどでテストすることもできます。
Xがボックス化されたintの場合、_(int)x
_が最も高速です。
Xが文字列であるが、確かに有効な数値である場合、int.Parse(x)
が最適です
Xが文字列であるが有効ではない場合、int.TryParse(x)
はtry-catchブロックよりもはるかに高速です。
ParseとTryParseの違いは、非常に大きなループを除いてすべて無視できます。
Xが何か(文字列またはボックス化されたint)がわからない場合は、Convert.ToInt32(x)
が最適です。
これらの一般化されたルールは、静的なParseおよびTryParseメソッドを使用するすべての値タイプにも当てはまります。
最速!=ベストプラクティス!
たとえば、_(int)
_は関数呼び出しではなく演算子であるため、ほぼ間違いなく最速ですが、特定の状況でのみ機能します。
ベストプラクティスは、パフォーマンスに悪影響を与えない読み取り可能なコードを使用することであり、100のうち99倍の整数変換では効果がありません。アプリのパフォーマンス。そうである場合は、できる限り適切で最も狭い変換を使用してください。時々それは_(int)
_です。時々それはTryParse()
です。時々それはConvert.ToInt32()
です。
データが間違いなくintであることがわかっている場合は、int myInt = (int)x;
が最も高速なオプションです。それ以外の場合は、TryParse
を使用すると、例外を遅らせることなく正しく実行できます。
ところで:
(int)unboxesのみなので、より速く、
(int)IL =
.locals init (
[0] object x,
[1] int32 Y)
L_0000: ldc.i4.1
L_0001: box int32
L_0006: stloc.0
L_0007: ldloc.0
L_0008: unbox int32
L_000d: ldobj int32
L_0012: stloc.1
L_0013: ret
Convert.Toint32 =
.locals init (
[0] object x,
[1] int32 Y)
L_0000: ldc.i4.1
L_0001: box int32
L_0006: stloc.0
L_0007: ldloc.0
L_0008: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
L_000d: call int32 [mscorlib]System.Convert::ToInt32(object)
L_0012: stloc.1
L_0013: ret
このような特定のことを実行するさまざまな方法のパフォーマンスの違いについて質問がある場合、私は通常、MeasureItのコピーに新しいエントリを作成します。これは、Vance Morrisonのすばらしい MSDN記事 から無料でダウンロードできます。詳細については、記事を参照してください。
MeasureItに簡単なコードを追加すると、以下の結果が得られ、intに変換するさまざまな方法の実際のタイミングが比較されます。 stringからintへのキャストは例外をスローして無効になるので、意味のある順列を追加しただけであることに注意してください。
名前中央値平均標準偏差最小最大サンプル IntCasts:Copy [count = 1000 scale = 10.0] 0.054 0.060 0.014 0.054 0.101 10 IntCasts:Cast Int [count = 1000 scale = 10.0] 0.059 0.060 0.007 0.054 0.080 10 IntCasts:Cast Object [count = 1000 scale = 10.0] 0.097 0.100 0.008 0.097 0.122 10 IntCasts:int.Parse [count = 1000 scale = 10.0] 2.721 3.169 0.850 2.687 5.473 10 IntCasts:Convert.ToInt32 [count = 1000 scale = 10.0] 3.221 3.258 0.067 3.219 3.418 10
興味のあるさまざまなタイプの最高のパフォーマンスを見つけるには、以下のコードを拡張するだけです。これは、上記のテーブルを生成するためにMeasureItに文字通り追加する必要があるすべてのコードです。
static unsafe public void MeasureIntCasts()
{
int result;
int intInput = 1234;
object objInput = 1234;
string strInput = "1234";
timer1000.Measure("Copy", 10, delegate
{
result = intInput;
});
timer1000.Measure("Cast Object", 10, delegate
{
result = (int)objInput;
});
timer1000.Measure("int.Parse", 10, delegate
{
result = int.Parse(strInput);
});
timer1000.Measure("Convert.ToInt32", 10, delegate
{
result = Convert.ToInt32(strInput);
});
}
ベストプラクティスはTryParseであり、それが機能する場合はその結果を確認します。それ以外の場合は例外が発生します。
.Net 2でバインドされたデータグリッドを最適化すると、さまざまなオブジェクトのToString()メソッドに費やされる時間のほぼ半分が、変換操作の入力として使用されることがわかりました。これらのケースを分離し、可能な場合は正しいタイプにキャストすることで(データベースから取り出された行であり、タイプが信頼できるため)、これにより、データバインディング操作の速度が大幅に向上しました。
したがって、事物のタイプが前もってわかっていて、コードに十分な回数ヒットする場合は、必要に応じて変換する代わりに、コードを直接キャストする価値があります。
Eric Coskyのテストを Sam Allenの代替 で拡張すると、文字列が有効な整数であることがわかっている場合は、自分で解析する方がはるかに高速です。
私は以下の場合でテストを拡張しました:
timer1000.Measure("IntParseFast", 10, delegate
{
result = Misc.IntParseFast(strInput);
});
timer1000.Measure("IntParseUnsafe", 10, delegate
{
result = Misc.IntParseUnsafe(strInput);
});
次の実装では:
public static int IntParseFast(string value)
{
int result = 0;
int length = value.Length;
for (int i = 0; i < length; i++)
{
result = 10 * result + (value[i] - 48);
}
return result;
}
public unsafe static int IntParseUnsafe(string value)
{
int result = 0;
fixed (char* v = value)
{
char* str = v;
while (*str != '\0')
{
result = 10 * result + (*str - 48);
str++;
}
}
return result;
}
次の結果が得られます。
IntCaint.Parse 5,495
IntCaConvert.ToInt32 5,653
IntCaIntParseFast 1,154
IntCaIntParseUnsafe 1,245
本当じゃない。高速変換は直接キャストです:
int i = (int) stringData;
watch.Elapsed = {00:00:00.1732388}
watch2.Elapsed= {00:00:00.0878196}
// Mesary start
Stopwatch watch = new Stopwatch();
watch.Start();
for (int f = 1; f < 1000000; f++)
{
item.Count = FastInt32.IntParseFast(dt.Rows[i]["TopCount"]);
} // Execute the task to be timed
watch.Stop();
Console.WriteLine("Elapsed: {0}", watch.Elapsed);
Console.WriteLine("In milliseconds: {0}", watch.ElapsedMilliseconds);
Console.WriteLine("In timer ticks: {0}", watch.ElapsedTicks);
// Mesary end
// Mesary start
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (int n = 1; n < 1000000; n++)
{
item.Count = (int)(dt.Rows[i]["TopCount"]);
} // Execute the task to be timed
watch2.Stop();
Console.WriteLine("Elapsed: {0}", watch2.Elapsed);
Console.WriteLine("In milliseconds: {0}", watch2.ElapsedMilliseconds);
Console.WriteLine("In timer ticks: {0}", watch2.ElapsedTicks);
// Mesary end
パフォーマンスについてはわかりませんが、これらの方法はまったく同じではありません。 Parse
とTryParse
はどちらも文字列で動作し、オブジェクトのString
表現は解析されます(MSDNを参照)。
数値の文字列表現を32ビットの符号付き整数に変換します。
キャストとConvert
クラスについては不明ですが、キャストは実際にはすでに整数であるが強く型付けされていないオブジェクトに対してのみ行われます。
マティアス
追加の速度が必要な場合は、さまざまなオプションを簡単にテストできます。それらをテストしていないので、それらを必要としてはなりません。無意味なマイクロ最適化で時間を無駄にしないでください!
(int)文字列の変換は機能しないため、テストしません。 Convert.ToInt32は、値をnullにテストし、THENがint.Parseを呼び出すことを反映しているため、一般にint.Parse()よりも低速になる傾向があります。
foreach(DataRow row in someTable.Rows)
{
myInt = (int)row["some int value"];
myInt2 = Int.Parse(row["some int value"]);
myInt2 = Convert.ToInt32(row["some int value"]);
}
この例では、テーブルからの値が実際にint値、または同等のデータベース値である場合、
myInt = (int)row["some int value"];
最も効率的であり、したがって「最速」であるため
row["some int value"];
参照型のオブジェクトインスタンス内にボックス化された値型のintインスタンスになるため、明示的な型キャストを使用すると、関数呼び出しではない操作であると他の人が言っているので最も速く、必要なCPU操作を減らすことができます。変換または解析メソッドの呼び出しは、追加のCPU操作を必要とするため、「高速」ではありません。