Извините за длинный вопрос, но есть ссылка на Джона Скита, так что для некоторых это может оказаться полезным.
Короче говоря:
Interlocked.Read
/ Interlocked.Exchange
, кажется, работает намного медленнее при работе в среде Mono, чем при работе в среде .NET. Мне любопытно узнать почему.
В длинну:
Я хотел получить потокобезопасный double для 32-битных платформ, поэтому я создал следующую структуру:
public interface IThreadSafeDouble
{
double Value { get; set; }
}
public struct LockedThreadSafeDouble : IThreadSafeDouble
{
private readonly object Locker;
private double _Value;
public double Value
{
get { lock (Locker) return _Value; }
set { lock (Locker) _Value = value; }
}
public LockedThreadSafeDouble(object init)
: this()
{
Locker = new object();
}
}
Затем я прочитал ответ Джона Скита на на этот вопрос , поэтому я создал следующую структуру:
public struct InterlockedThreadSafeDouble : IThreadSafeDouble
{
private long _Value;
public double Value
{
get { return BitConverter.Int64BitsToDouble(Interlocked.Read(ref _Value)); }
set { Interlocked.Exchange(ref _Value, BitConverter.DoubleToInt64Bits(value)); }
}
}
Тогда я написал этот тест:
private static TimeSpan ThreadSafeDoubleTest2(IThreadSafeDouble dbl)
{
var incrementTarg = 10000000;
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < incrementTarg; i++, dbl.Value++);
sw.Stop();
return sw.Elapsed;
}
private static void ThreadSafeTest()
{
var interlockedDbl = new InterlockedThreadSafeDouble();
var interlockedTim = ThreadSafeDoubleTest2(interlockedDbl);
var lockedDbl = new LockedThreadSafeDouble(true);
var lockedTim = ThreadSafeDoubleTest2(lockedDbl);
System.Console.WriteLine("Interlocked Time: " + interlockedTim);
System.Console.WriteLine("Locked Time: " + lockedTim);
}
public static void Main(string[] args)
{
for (var i = 0; i < 5; i++)
{
System.Console.WriteLine("Test #" + (i + 1));
ThreadSafeTest();
}
System.Console.WriteLine("Done testing.");
System.Console.ReadLine();
}
И я получил этот результат, используя .NET Framework:
И этот результат с использованием фреймворка Mono:
Я выполнил оба теста несколько раз на одной машине (Windows XP), и результаты совпадают. Мне любопытно узнать, почему Interlocked.Read/Interlocked.Exchange, кажется, работает намного медленнее в платформе Mono.
Обновление:
Я написал следующий, более простой тест:
long val = 1;
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 100000000; i++) {
Interlocked.Exchange(ref val, 2);
// Interlocked.Read(ref val);
}
sw.Stop();
System.Console.WriteLine("Time: " + sw.Elapsed);
.NET Framework последовательно возвращает ~ 2,5 секунд с Exchange
и Read
. Моно каркас возвращает ~ 5,1 секунд.