Ответ 1
Если вы хотите извлечь из изображения кеш L2 и пропуски TLB, тогда просто вызовите второй тест на другой MemoryStream того же размера.
У меня есть этот код, который при замене порядка 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
Помимо запуска их независимо, как сделать недействительным кеш, чтобы второй тестируемый код не получал кэшированную память первого кода?
Сравнительный анализ, просто понравился тот факт, что современные процессоры делают эту кеширующую магию: -)
[EDIT]
Как рекомендуется попробовать этот более быстрый код (предположительно)...
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
Медленнее, чем два кода выше
[EDIT]:
Как посоветовали вручить каждой рутине свою собственную копию...
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 миллисекунд), когда им передают свою собственную копию массива, я ничего не могу сделать из этого:-) Это совсем другая история
Если вы хотите извлечь из изображения кеш L2 и пропуски TLB, тогда просто вызовите второй тест на другой MemoryStream того же размера.