www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - an extremely naive question regarding synchronized...

reply WhatMeWorry <kheaser gmail.com> writes:
I was reading this fasciniating article:

https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/

And to quote a section of it:
-----------------------------------------------------
static MySingleton get() {
     synchronized {
       if (instance_ is null) {
         instance_ = new MySingleton;
       }
     }
     return instance_;
   }

Now, if Thread 1 calls get(), it has a chance to finish 
instantiating instance_ and storing a reference to it before 
Thread 2 checks whether instance_ is null.  There’s only one 
problem with this:  It comes at a huge performance cost 
(benchmarks forthcoming).  Entering a synchronized block is 
expensive.
-----------------------------------------------------

Why is the synchronized block so expensive?  Isn't it just doing 
one conditional and a new command?  Again, to my naive way of 
thinking, this seems like a very small blocking window.

And the graph shows 1B get() calls.  I assume B stands for 
billion.  What use case would require so many gets?

Thanks.
Nov 14 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 11/14/16 12:43 PM, WhatMeWorry wrote:
 I was reading this fasciniating article:

 https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/

 And to quote a section of it:
 -----------------------------------------------------
 static MySingleton get() {
     synchronized {
       if (instance_ is null) {
         instance_ = new MySingleton;
       }
     }
     return instance_;
   }

 Now, if Thread 1 calls get(), it has a chance to finish instantiating
 instance_ and storing a reference to it before Thread 2 checks whether
 instance_ is null.  There’s only one problem with this:  It comes at a
 huge performance cost (benchmarks forthcoming).  Entering a synchronized
 block is expensive.
 -----------------------------------------------------

 Why is the synchronized block so expensive?  Isn't it just doing one
 conditional and a new command?  Again, to my naive way of thinking, this
 seems like a very small blocking window.
It's expensive when compared to simply reading a piece of memory. synchronized means that the CPU core has to sync it's view of memory with the memory manager and all the other CPUs in the system.
 And the graph shows 1B get() calls.  I assume B stands for billion.
 What use case would require so many gets?
This is a typical technique with benchmarking to show some measurable results. If it had, say 10 gets, the noise of context switching, or of different various things running in the OS could sway the graph a huge amount. Not to mention that time measurement on an OS is in discrete units that may not even capture the short time to do 10 gets. In other words, if your stopwatch only has a second hand, and it takes 1 ms to do something, you need to repeat that thing 10,000 times in order to properly measure it. -Steve
Nov 14 2016
prev sibling next sibling parent reply Kapps <opantm2+spam gmail.com> writes:
On Monday, 14 November 2016 at 17:43:37 UTC, WhatMeWorry wrote:
 I was reading this fasciniating article:

 https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/

 And to quote a section of it:
 -----------------------------------------------------
 static MySingleton get() {
     synchronized {
       if (instance_ is null) {
         instance_ = new MySingleton;
       }
     }
     return instance_;
   }

 Now, if Thread 1 calls get(), it has a chance to finish 
 instantiating instance_ and storing a reference to it before 
 Thread 2 checks whether instance_ is null.  There’s only one 
 problem with this:  It comes at a huge performance cost 
 (benchmarks forthcoming).  Entering a synchronized block is 
 expensive.
 -----------------------------------------------------

 Why is the synchronized block so expensive?  Isn't it just 
 doing one conditional and a new command?  Again, to my naive 
 way of thinking, this seems like a very small blocking window.

 And the graph shows 1B get() calls.  I assume B stands for 
 billion.  What use case would require so many gets?

 Thanks.
Keep in mind, this is only slow for such a large amount of calls. If you're calling this only a hundred times a second, then who cares if it's slower. After all, with GDC we were looking at 1 billion calls in 21 seconds. That's 47,000 calls per *millisecond*.
Nov 15 2016
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 11/15/16 3:05 PM, Kapps wrote:

 Keep in mind, this is only slow for such a large amount of calls.
 If you're calling this only a hundred times a second, then who cares if
 it's slower. After all, with GDC we were looking at 1 billion calls in
 21 seconds. That's 47,000 calls per *millisecond*.
This is the wrong way to look at it. If you are calling it from one thread, then 100 times/second is no problem. If you have 100 threads calling it 100 times a second, you have killed any performance gained by using threads in the first place. The reason lock-free singletons are so attractive is because of the allowance of multiple threads to use it at the same time without contention. It's why years of "slightly wrong" advice on singletons has been out there, and why this solution is so amazing in its simplicity. -Steve
Nov 15 2016
prev sibling parent Kagamin <spam here.lot> writes:
   static MySingleton get() {
     if (instance_ is null) {
       synchronized {
         if (instance_ is null) {
           atomicStore(instance_, new MySingleton);
         }
       }
     }
     return instance_;
   }

This should work fine and faster.
Nov 16 2016