Как неверно использовать кэш при сравнении?
-
30-09-2019 - |
Вопрос
У меня есть этот код, что при замене заказа на использование и с использованием их производительность также сводится.
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
Помимо пробега их самостоятельно, как недействительный Кэш, поэтому второй код, который называется, не получит кэшированную память первого кода?
Безонмаркинг в сторону, просто любил тот факт, что современные процессоры делают эту кэширование магии :-)
РЕДАКТИРОВАТЬ
Как рекомендуется попробовать этот более быстрый код (предположительно) ...
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
Медленнее, чем два кода выше
РЕДАКТИРОВАТЬ]:
Как посоветовали передать каждую рутину свою копию ...
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!
Запуск литья и как независимо, они также дают один и тот же результат (т.е. 282). Теперь, как и за то, почему они становятся Быстрее (от 322 до 282 миллисекунд), когда они передают свою собственную копию массива, я не могу ничего сделать из этого :-) Это совершенно другая история
Решение
Если вы хотите вывести из картинки, кэш L2 и промахи TLB просто просто позвоните второму тесту на другой память одинакового размера.