Queue.Synchonized
При запросе вы получите SynchronizedQueue
в ответ, который использует lock
очень минимально вокруг вызывает к Enqueue
и Dequeue
на внутренней очереди. Таким образом, производительность должна быть такой же, как с использованием Queue
и управления блокировкой для Enqueue
и Dequeue
с вашим собственным lock
.
Вы действительно представляете вещи - они должны быть одинаковыми.
Update
Существует на самом деле тот факт, что при использовании SynchronizedQueue
вы добавляете слой косвенности, как вы должны пройти через методу обертки, чтобы добраться до внутренней очереди которой он управляет. Если что-либо, это должно замедлить работу до минимума, поскольку у вас есть дополнительный фрейм в стеке, который нужно управлять для каждого вызова. Бог знает, что если подкладка не отменяет этого. Неважно - это минимальный.
Update 2
Я теперь протестированные это, и, как предсказано в моем предыдущем обновлении:
"Queue.Synchronized" медленнее, чем "Очередь + блокировка"
Я выполнил однопоточный тест, поскольку оба они используют одну и ту же технологию блокировки (то есть lock
), поэтому тестирование чистых накладных расходов на «прямой линии» представляется разумным.
Мой тест дает следующие результаты для выпуска сборки:
Iterations :10,000,000
Queue+Lock :539.14ms
Queue+Lock :540.55ms
Queue+Lock :539.46ms
Queue+Lock :540.46ms
Queue+Lock :539.75ms
SynchonizedQueue:578.67ms
SynchonizedQueue:585.04ms
SynchonizedQueue:580.22ms
SynchonizedQueue:578.35ms
SynchonizedQueue:578.57ms
Используя следующий код:
private readonly object _syncObj = new object();
[Test]
public object measure_queue_locking_performance()
{
const int TestIterations = 5;
const int Iterations = (10 * 1000 * 1000);
Action<string, Action> time = (name, test) =>
{
for (int i = 0; i < TestIterations; i++)
{
TimeSpan elapsed = TimeTest(test, Iterations);
Console.WriteLine("{0}:{1:F2}ms", name, elapsed.TotalMilliseconds);
}
};
object itemOut, itemIn = new object();
Queue queue = new Queue();
Queue syncQueue = Queue.Synchronized(queue);
Action test1 =() =>
{
lock (_syncObj) queue.Enqueue(itemIn);
lock (_syncObj) itemOut = queue.Dequeue();
};
Action test2 =() =>
{
syncQueue.Enqueue(itemIn);
itemOut = syncQueue.Dequeue();
};
Console.WriteLine("Iterations:{0:0,0}\r\n", Iterations);
time("Queue+Lock", test1);
time("SynchonizedQueue", test2);
return itemOut;
}
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect")]
private static TimeSpan TimeTest(Action action, int iterations)
{
Action gc =() =>
{
GC.Collect();
GC.WaitForFullGCComplete();
};
Action empty =() => { };
Stopwatch stopwatch1 = Stopwatch.StartNew();
for (int j = 0; j < iterations; j++)
{
empty();
}
TimeSpan loopElapsed = stopwatch1.Elapsed;
gc();
action(); //JIT
action(); //Optimize
Stopwatch stopwatch2 = Stopwatch.StartNew();
for (int j = 0; j < iterations; j++) action();
gc();
TimeSpan testElapsed = stopwatch2.Elapsed;
return (testElapsed - loopElapsed);
}
Просто вынимая замок с помощью любого из методов, это безумно быстро. Выигрыш производительности зависит от того, сколько споров для замков. – serg10