Is Queue.Synchronized faster than using Lock ()?

I have a queue in which an Enqueue operation will be executed by one thread, and a Dequeue will be executed by another. Needless to say, I had to implement some thread safety.

At first I tried to use the lock in the queue before each Enqueue / Dequeue, as it gives better control over the locking mechanism. It worked well, but my curious mind made me check something else.

Then I tried using Queue.Synchronized wrapper while preserving everything else. Now I'm not sure if this is true, but performance with this approach looks a little faster.

Do you think there really is any difference in performance between the two, or am I just introducing things here ...? :)

+7
source share
3 answers

When you query Queue.Synchonized you get a returned SynchronizedQueue that uses lock very minimally around Enqueue and Dequeue in the internal queue. Therefore, the performance should be the same as when using Queue and manage the lock for Enqueue and Dequeue using its own lock .

You really imagine things - they must be the same.

Update

In fact, there is the fact that when using SynchronizedQueue you add an indirect layer, since you need to go through wrapper methods to get to the internal queue that it controls. If anything, this should slow down to a minimum, since you have an extra frame on the stack that needs to be managed for each call. God knows that if the lining does not cancel it. Whatever it is - minimal.

Update 2

Now I have compared this and, as was predicted in my previous update:

"Queue.Synchronized" is slower than "Queue + lock"

I performed a single-threaded test because both of them use the same locking method (ie lock ), so testing a clean invoice in a โ€œstraight lineโ€ seems reasonable.

In my test, the following results were obtained for the Release build:

 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 

Using the following code:

 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); } 
+16
source

We cannot answer this for you. Only you can answer it yourself by receiving a profiler and checking both scripts ( Queue.Synchronized vs. Lock ) on real data from your application. This may not even be a bottleneck in your application.

However, you should probably just use ConcurrentQueue .

+6
source
  • Queue.Synchronize Wraps a new queue Synchronizes during blocking Queue.SyncRoot gives the object access to the synchronized queue, so that you can ensure thread safety in the queue while using Enqueue and Dequeue operations using Threads.
0
source

All Articles