30

次の質問への回答: MatchCollectionを文字列配列に変換する方法

2つのLinq式が与えられた場合:

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .OfType<Match>() //OfType
    .Select(m => m.Groups[0].Value)
    .ToArray();

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .Cast<Match>() //Cast
    .Select(m => m.Groups[0].Value)
    .ToArray();

OfType <>は、ユーザーAlexによってわずかに高速であるとベンチマークされました(そして私自身によって確認されました)。

OfType <>は'is'比較とキャスト(T)の両方を実行する必要があると思っていたので、これは私には直感に反しているようです。

なぜこれが当てはまるのかについての啓蒙をいただければ幸いです:)

4

4 に答える 4

16

私のベンチマークはあなたのベンチマークと一致しません。

アレックスと同じベンチマークを実行したところ、反対の結果が得られました。次に、ベンチマークをいくらか微調整したところCastOfType.

それほど多くはありませんがCast、反復子がより単純であるため、当然のことながら、優位性があると思います。(isチェックなし)

編集:実際には、さらに微調整した後CastOfType.

以下は、これまでに見つけた最大の不一致を示すベンチマークのコードです。

Stopwatch sw1 = new Stopwatch();
Stopwatch sw2 = new Stopwatch();

var ma = Enumerable.Range(1, 100000).Select(i => i.ToString()).ToArray();

var x = ma.OfType<string>().ToArray();
var y = ma.Cast<string>().ToArray();

for (int i = 0; i < 1000; i++)
{
    if (i%2 == 0)
    {
        sw1.Start();
        var arr = ma.OfType<string>().ToArray();
        sw1.Stop();
        sw2.Start();
        var arr2 = ma.Cast<string>().ToArray();
        sw2.Stop();
    }
    else
    {
        sw2.Start();
        var arr2 = ma.Cast<string>().ToArray();
        sw2.Stop();
        sw1.Start();
        var arr = ma.OfType<string>().ToArray();
        sw1.Stop();
    }
}
Console.WriteLine("OfType: " + sw1.ElapsedMilliseconds.ToString());
Console.WriteLine("Cast: " + sw2.ElapsedMilliseconds.ToString());
Console.ReadLine();

私が行った微調整:

  • 「文字列のリストを生成する」作業を最初に一度行い、それを「結晶化」します。
  • タイミングを開始する前に各操作の 1 つを実行します。これが必要かどうかはわかりませんが、JITter がタイミングを取っている間ではなく、事前にコードを生成することを意味していると思いますか?
  • 各操作を 1 回だけでなく、複数回実行します。
  • これが違いを生む場合に備えて、順序を変更します。

私のマシンでは、これにより が ~350ms、 がCast~18000ms になりOfTypeます。

最大の違いはMatchCollection、次の一致を見つけるのにかかる時間を計測しなくなったことです。(または、私のコードでは、どれくらいint.ToString()時間がかかりますか。)これにより、信号対雑音比が大幅に低下します。

Cast編集: sixlettervariablesが指摘したように、この大きな違いの理由は、IEnumerable. Regex.Matches正規表現の処理時間を測定することを避けるために使用から配列に切り替えたときに、キャスト可能なものを使用するように切り替えたためIEnumerable<string>、この短絡がアクティブになりました。ベンチマークを変更してこのショートサーキットを無効にすると、大きなアドバンテージではなく、わずかアドバンテージが得られます。Cast

于 2012-07-11T12:04:34.047 に答える
7

OfTypeメソッドのandの順序を逆にするだけでCast、違いがないことに気付くでしょう。最初のものは常に 2 番目のものよりも速く実行されます。これは悪いマイクロベンチマークのケースです。

コードをループでラップして、ランダムな順序で実行します。

OfType: 1224
Cast: 2815
Cast: 2961
OfType: 3010
OfType: 3027
Cast: 2987
...

そして再び:

Cast: 1207
OfType: 2781
Cast: 2930
OfType: 2964
OfType: 2964
OfType: 2987
...

Regex.Matches問題の原因と思われる を持ち上げます。

Cast: 1247
OfType: 210
OfType: 170
Cast: 171
...

OfType: 1225
Cast: 202
OfType: 171
Cast: 192
Cast: 415

いいえ。OfTypeは より速くありませんCast。いいえ、Castより速くはありませんOfType

于 2012-07-11T13:17:50.767 に答える
1

実際には、 isof() は最初に型をチェックしてからキャストしますが、 as cast() は 2 番目の部分だけを行います。したがって、明らかに isof() は直接キャストよりも遅くなります

http://codenets.blogspot.in/2010/06/cast-vs-oftype.html

于 2012-07-11T12:04:21.907 に答える