UsingAs と UsingCast の順序を入れ替えると、そのパフォーマンスも入れ替えられるというこのコードがあります。
using System;
using System.Diagnostics;
using System.Linq;
using System.IO;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new MemoryStream[Size];
UsingAs(values);
UsingCast(values);
Console.ReadLine();
}
static void UsingCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is MemoryStream)
{
var m = (MemoryStream)o;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
static void UsingAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is MemoryStream)
{
var m = o as MemoryStream;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
}
出力:
As: 0 : 322
Cast: 0 : 281
これを行うと...
UsingCast(values);
UsingAs(values);
...結果は次のとおりです。
Cast: 0 : 322
As: 0 : 281
これだけやると…
UsingAs(values);
...結果は次のとおりです。
As: 0 : 322
これだけを行う場合:
UsingCast(values);
...結果は次のとおりです。
Cast: 0 : 322
それらを個別に実行する以外に、キャッシュを無効にして、ベンチマークされている2番目のコードが最初のコードのキャッシュされたメモリを受信しないようにする方法は?
ベンチマークはさておき、最新のプロセッサがこのキャッシング マジックを行うという事実が気に入りました :-)
[編集]
このより高速なコードを試すようにアドバイスされているように(おそらく)...
static void UsingAsAndNullTest(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
var m = o as MemoryStream;
if (m != null)
{
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As and null test: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
...結果は次のとおりです。
As and null test: 0 : 342
上記の 2 つのコードより遅い
[編集]:
各ルーチンに独自のコピーを渡すことをお勧めします...
static void UsingAs(object[] values)
{
object[] a = values.ToArray();
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in a)
{
if (o is MemoryStream)
{
var m = o as MemoryStream;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
static void UsingCast(object[] values)
{
object[] a = values.ToArray();
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in a)
{
if (o is MemoryStream)
{
var m = (MemoryStream)o;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
...出力:
Cast: 0 : 282
As: 0 : 282
今では同じ結果になりました、Remus に感謝します!
Cast と As を個別に実行しても、同じ結果 (つまり 282) が得られます。さて、配列の独自のコピーを渡されたときになぜ速くなったのか (322 ミリ秒から 282 ミリ秒まで) については、私はそれから何も理解できません :-) それはまったく別の話です