Hi, at 1 minute in the video there's this piece of code: if (_instance is not null) { return _instance; } return _instance ??= new Manager(); Why the if statement? Doesn't the null-coalescing already cover it thus make it redundant? I'm kind of new to C# programming and I'm asking maybe I'm missing something.
@S1lenc31991Күн бұрын
You are correct
@diadetediotedio6918Күн бұрын
lol, true, I think he missed it and maybe that's also part of his benchmark results hah
@nickchapsasКүн бұрын
Valid point I missed it when I moved it to Rider because originally I had implemented locking to make it thread safe but I removed it last minute to have more accurate benchmarks. It shouldn’t affect the benchmarks in any meaningful way (I will have to check if the JIT will optimise one of the checks out) and the point of the video isn’t just about the performance difference but the use-case differences
@nathansmela194Күн бұрын
@@nickchapsas guess you could call this "Nick-picking"
@dfbdtrhgwtwd7149Күн бұрын
In any case, that is not the best way to define a Singleton in C#. At very least, that approach is not thread safe. There are better ways to do that.
@RohitMoniКүн бұрын
Chiming in from someone who works in gaming: the difference is small but I think it's definitely something we'd care about (in context). Because: 1. A single call might not make much of a difference, but singleton managers like this are often accessed many times from all over the place. The cost can stack up. 2. The cost to implementing this optimization is minimal (trivial basically) and the cost to readability and maintainability is also almost nil. That makes this kind of premature optimization more worth doing all the time. 3. (Context based) If you're building a general purpose library or system that's intended for use by others, the more performance you eke out the more variability you allow your end users (they can be sloppier with their code). But ultimately, this is all in gaming, where you have 16ms to do your frame (60fps) and many individual subsystems have budgets in the 2-5ms range.
@NavhkrinКүн бұрын
Singletons are actually bad pattern for game systems. Performance difference here is irrelevant even if you access singleton 1000 times per frame. More importantly you lose granularity of system initialization & deinitialization. You usually want a clearer control over when systems are initialized & deinitialized than what a singleton provides. Lastly, if you worry about performance diff of 0.5ns, you should be writing C++ anyways. And you can always just cache the pointers
@zorglugКүн бұрын
Your second point is the most important here, imo. There are no downsides to caching, so it shouldn't even be a question. That's not what premature optimization means, anyway. In general, if a faster way exists (however minimal of an impact it makes) and it doesn't impact the structure of the code to make the change, just do the faster thing. I spent more time writing this reply than it takes to cache a variable, lol! It's so weird that people argue about this.
@davidmartensson27311 сағат бұрын
@@zorglug Agreed, premature means optimizing before you know if it will be useful or even the correct solution. If its always going to improve things, takes no time to add and does not reduce readability and its very very unlikely to be changed later on in development then adding it is not premature, just best practice :)
@_nikeeeКүн бұрын
The singleton you come up with is a special type of singleton: a _lazy_ singleton. A non-thread-safe in particular, because .Instance can be called from multiple threads. If the ctor takes time (which it probably does, because that's often why you are using a singleton), then _instance will be null if a second thread calls .Instance, resulting in two invocations of the ctor. You should Lazy for lazy singleton init.
@nickchapsasКүн бұрын
Watch until the end
@sealsharpКүн бұрын
It's a unity example. You could remove the nullcheck and create that thing once at game-init where it's guaranteed to be called from the main thread before anything concurrent ever happens.
@dsowaКүн бұрын
Just to mention, the shown singleton pattern is not thread-save!
@nickchapsasКүн бұрын
Watch until the end
@nage7447Күн бұрын
totally agree ) 1:00 btw this operator checks for null as well, basically you do not need if check before it and it would work the same
@freddyflares275710 сағат бұрын
This is where I miss coding in assembler. You can write self-modifying code to overwrite the null check on first execution.
@zevspitz8925Күн бұрын
Instead of having a getter with a null-check, initialize a readonly field either with a static constructor or a field expression, and expose that field as public.
@leandroteles7857Күн бұрын
If your Singleton is a static readonly field instead of a getter, then you should have close-to-zero overhead, because at runtime it's just going to be an extra pointer dereference. Also you can have some overhead if the JIT is unable to inline the Singleton getter. To avoid that, the bulk of the initialization work should be in a separate method, and the getter should have only the null check + method call. But static readonly is usually the best approach. You're effectively delegating the "is initialized" check to the JIT itself.
@renauddanniau676Күн бұрын
Could you elaborate a little more about why having a method where the initialization occurs helps the inlining ? I assume you mean something like this : get => if(instance is null) {instance = BuildInstance();) return instance; Why having the BuildInstance method will improve the likelihood of inlining ?
@leandroteles785723 сағат бұрын
@@renauddanniau676 Because not everything can be inlined, for example, methods won't be inlined if they are too big, or if they have any try-catch blocks. With this approach, BuildInstance itself may not be inlined, but it's fine, cause it's invoked only once. The singleton getter will very likely get inlined.
@renauddanniau67613 сағат бұрын
@leandroteles7857 Can I ask where you've learned that ? I also sometimes check the produced IL with no sign of inlining so, I'm wondering ;). Thank-you!
@leandroteles785710 сағат бұрын
@@renauddanniau676 Inlining doesn't happen at IL, it happens at JIT time, when IL is translated into machine code. As for the source, I'm not sure if the inlining behavior is documented, I just remember reading somewhere that exception handlers prevent method inlining, and I also tested it. Usually when I want to know about inlining I just test it in Sharplab. Set it to Release, and mark your method with AggressiveInlining, if it doesn't get inlined that way, then it can't be.
@DJHightower77Күн бұрын
wtf - yt translates the title and description automatically now? How can i disable that?
@nickchapsasКүн бұрын
The question is where do I disable that. It looks like it was auto activated for every channel on KZbin
@AngeloTadeucciКүн бұрын
I think for now, the only way is to change your youtube language
@1smuelКүн бұрын
kzbin.info/www/bejne/hpyZZISDiN6abc0si=mGBOlAcDTBig_IYR Shows how to disable it for creators starting after 6:43
@BlyZeHDКүн бұрын
Here at statischvssingleton
@dragonyt73Күн бұрын
Me too, never do that again please.
@dragons_advocateКүн бұрын
I would advise against holding state in a static class, not because it wouldn't work, but because it can get ugly fast. I worked on a codebase where dozens of "global variables" were aggregated as public static in a static class.... debugging was a nightmare.
@warny1978Күн бұрын
It would be better initializing the singleton in the static constructor. Just keep in mind that static constructor messes up with the debugger when it throws an exception. Also you dont need a if before return _instance ?== new Manager() as this line aleready tests if _instance is null.
@maushaxКүн бұрын
>Mentions a possible "solution" for singleton initialization. >Also states why should be avoided that "solution". LMAO
@warny1978Күн бұрын
@maushax i don't say that you should avoid that solution, just that constructors must be kept fucking simple unless you want to fight against the debugger.
@M4psterКүн бұрын
I've been a professional unity dev for almost 10 years and have seen all kinds of code bases and optimizations. Singletons are extremely common where an instance lives on a static field. The only time I've seen caching that instance makes a difference (and even then extremely uncommon) is in highly complex functions that do many many calculations. And even then, you might squeeze 2ms out of something that only happens once every 5 minutes on an extremely old mobile phone. Like the redit comment said. There's other stuff to invest your time in, and this is something to forget about. To understand the problem then unity calls "benchmarking" "profiling".
@TortuapКүн бұрын
You probably meant 2us. 2ms is huge in a frame time allocation.
@M4psterКүн бұрын
@Tortuap unity only shows ms sadly. 2ms is huge i agree. So in my example of a highly complex method its a huge win but even then thats in a extremely specific case and even then would only affect low spec devices like nintendo switch or very old phones.
@Moosa_SaysКүн бұрын
Your singleton is not thread safe. Usually, you wrap initialization inside a lock statement, or you would use Lazy class to initialize the singleton in a thread-safe manner. I think that would result in even more performance impact (maybe).
@Rick1045476 сағат бұрын
Best use lazy, getting this completely thread safe can be surprisingly tricky as you need to prevent to expose partially initialized instances as well with extra memory barriers.
@JasonKaler5 сағат бұрын
I hate hiding code behind a getter, especially if that code has side-effects. I saw a post where the dev was trying to find out why he has a memory leak in unity. Turned out that the .material property creates a material each time you read it instead of returning the same one.
@АртемГрунин-н5нКүн бұрын
The only reason why static keyword exists is to guarantee that it will be initiated once in a thread safe manner. If you have a parameterless constructor, you should never have locking or double locking or whatever as it doesn't guarantee that your Instance will be created only once.
@NickSteffenКүн бұрын
Just out of curiosity why is the static backing field not initialized on startup. So instead of having a nullable backing you just set it equal to a new object right away. Then you can exclude the null check reducing the overhead to just a functional call. That function call would get inlined eventually by runtime optimization (usually 30 or so calls).
@xlerb2286Күн бұрын
We always used Autofac and their singleton pattern, which worked well for us. We had a method that did all the instantiation necessary to compose all the application components. These were business applications where wringing every last bit of performance out of the code generally wasn't necessary. But it made for a nice clean pattern and of course we had all the other DI goodness (and pain).
@tunawithmayoКүн бұрын
The problem I have with caching a singleton like that is that the code 'knows' something that it shouldn't, that the other class is a singleton.
@StefanHanrathКүн бұрын
There are multiple other important common problems to avoid with either singletons or statics on web servers: Thread safety is a must, especially if any kind of writes occur against your singleton obj. If you use a DI container with lifetimes, you may have a potential captive scope dependency problem to worry about. Outside of gaming or latency sensitive applications, i think the perf penalty is less important compared to the above 2 issues. An honorable 3rd place mention would be for me 'is the dependency you're referencing supposed to also be a singleton' as some objects carry properties that inherently imply multiples of them should exist. Other fun to cover material is inappropriate use of SDKs that are not necessarily designed to be transient lifetime, like the azure storage sdk.
@IllidanS4Күн бұрын
You should check the "standard" singleton pattern which is static readonly.
@RTGrangeКүн бұрын
I'll pick the singleton over the static class every time it's an option. Singletons can implement interfaces. They can be passed around as parameters. My only use for a static class at this point is if I need to make a set of extension methods.
@pedrogilmoraКүн бұрын
Why does it has 2 null checks? It has the "if is not null" and then nullish assignment?
@nickchapsasКүн бұрын
Yeah I missed it when I moved it to the IDE. Shouldn’t affect the benchmarks in any meaningful way and the point of the video still stands
@pedrogilmoraКүн бұрын
@nickchapsas will the first check get ignored?
@nickchapsasКүн бұрын
It sure how the compiler or the JIT will optimise them. I would have to check the ASM
@HarshColbyКүн бұрын
Question at the end: I usually use locks at initialization, out of habit. Probably not necessary in a lot of situations. But the performance hit is so minor, I just play it safe.
@dusrdevКүн бұрын
Your mention of the source generated DI is very interesting, can you make a video on it, with a library that you recommend?
@MilanDendisКүн бұрын
i use this for singletons in case i need it old way: public sealed class Singleton { // Static members are lazily initialized. // .NET guarantees thread safety for static initialization private static readonly Singleton _instance = new(); private Singleton() {} public static Singleton Instance() => _instance; public int DoSomething() { return System.Random.Shared.Next(); } } no need for double checking nor locking
@alexeydimov4423Күн бұрын
By the way, I think it's important to note that current version of Unity use Mono platform, and for benchmarking results to be completely valid for the Unity, it would be fair to run benchmarks on Mono. Though, I don't think for this specific case results would be drastically different anyways. More like an advice for those, who would want to benchmark other Unity stuff.
@ZullfixКүн бұрын
I think you should have run the benchmark a second time but using Mono. Mono is leagues behind .NET 9 and is notorious for producing _compliant_ code rather than _fast_ code. For example, Mono definitely would not inline the getter like many comments suggest, and it also wouldn't remove the second null check that was added by mistake. Both of those would probably add up to more than a single microsecond difference.
@szafer669Күн бұрын
Hi! I think I didn't hear it in the video so I will write about it here. If it was said then I must have missed it and I will remove this comment :) The example shows using this caching inside of a loop and not as a single-time thing. Properties are functions calls and they will always be slower than accessing a variable. This is negligible when this does not accumulate, but it is accumulating inside of loops like the one showed in this post. I have a professional experience in Unity and there were times when I had to do this type of caching to optimize. Mostly as a variable before the loop instead of a field but it doesn't change much. Thanks! :)
@ParsueКүн бұрын
Depends on. If a cycle update is necessary, I will inject a system to Unity LowLevel PlayerLoop. If it's a library, kindly create a static class. MonoBehaviour components are almost use to control game objects, renderable objects, or audios in my unity projects. So if there is a MonoBehaviour component which is really necessary and should be alive in the whole game (or application), I will make it as a Singleton.
@F1nalspaceКүн бұрын
Yeah nothing new here, but this is one reason why never ever put heavy load/code into any constructor! I don't expect that constructing a class instance or even a struct takes longer than some nanoseconds. But when i call something like Process(), Load(), Compute(), Initialize(), then i expect that i may take longer. Also nowadays in the C# world, heavy load activities should be async anyway, so when stuff happens inside the ctor you have to wrap it around a Task.Run() or something.
@davidmartensson27311 сағат бұрын
Most of the times I use singletons its through DI and many times it will start by loading a lot of resources, meaning you want to do that well in advance to trying to use that singleton.
@andreinikolaev75226 сағат бұрын
Hi, great video but I was expecting to see a difference between singleton call from our dependency injection container and classic static approach
@FoxsterdotaКүн бұрын
I suppose one "pro" of storing it as a variable rather than accessing .Instance could be that *that* specific consumer doesn't need to "worry" about it actually being a singleton or not, though of course that knowledge just gets pushed elsewhere. So if for whatever reason it changes to not be a singleton and as such loses its static .Instance method, then this particular consumer's code doesn't need to be modified. Extremely niche scenario but one minor, minor thing nevertheless.
@Alguem387Күн бұрын
Note You should not use the static field on Unity because of the MonoBehaviour lifecycle you can end up with weird initialization order dependent behavior since you cannot new up MonoBehaviors the static field always need to start off as null
@fusedqyouКүн бұрын
If your Monobehaviour gets destroyed then you did something wrong with your singleton setup. It should not be destroyed at all.
@igorsolomatov474319 сағат бұрын
Note, original question had internal loop, in that case basic variable would be a great choice. That though made me think about caching the entire delegate to that function, would that be faster? I remember there were techniques to make it real fast.
@cezarpimentelКүн бұрын
LOL, I clicked download and the video started with you speaking german! 🤣🤣🤣 Had to delete the video and download again
@Gobbenobber13 сағат бұрын
So if you used Lazy would that be more or less performant than the getter approach? Would be interesting to see. I can of course just go make the benchmarks myself but hey I am Lazy so yea not today xD
@Jaytonic3Күн бұрын
I'm curious, if you would use the static property instantiation(public static Manager Instance = new ()), would you have the same result? Since it does only initiatlize the static property on the first code, and then does not this "if" check?
@xRealHackerx23 сағат бұрын
Last period Nick’s videos could be interesting only for students. I personally expect more from a Microsoft MVP.
@Xerxesro1Күн бұрын
The singleton implementation is not only slower than it needs to be but also not thread safe. It's much better to use a static readonly field initialised and a static constructor. Then the property Instance simply returns the field, no need to check for null and it will likely be inlined.
@zevspitz8925Күн бұрын
Why not expose the field as public? Why do you need a property at all?
@TortuapКүн бұрын
It's obvious that caching a property value as a local variable is faster when used 10000 times. But there are so many intricated bottlenecks, so many optimizable algorithms in the 5% of video game runtime that needs to be optimized, that this optimization is not even at the end of the list of all the ones that needs to be done before.
@IingvarkaКүн бұрын
I thought you going to talk about state and locking in singleton from the title. It remind me of inline function in C you can reduce function call overhead at least
@derangedftw23 сағат бұрын
This video confused me for some reason. A game frameworks DI framework will almost equate to a Singleton instance in time to instantiate. Empty examples don't show real world examples.
@PanzerFaustFuriousКүн бұрын
doesn't unity use really old dotnet?
@CameronOwen10114 сағат бұрын
Its important to know what's happening under the hood but as a gane dev i would strongly discourage this kind of thinking at the time of writing the code. Thats the wrong time to be worried about those details. Sure there will be times when performance is a goal of a specific system but most of the time, thats just not the case. Step 1. Write game loop Step 2. Add featurs and profile every now and then so you learn your game/apps specific performance characteristics. Step 3: Make informed optimisation decisions only when you go over target (also, have hard performance targets) If this was a real problem and a real bottleneck it would stand out like a sore thumb when you profiled the game. Spending any amount of time thinking about this before you have a working game loop to profile is 100% wasted time and energy. There are a million little edge cases just like this that can net you a few cycle in microbenchs. You could spend an inordinate amount of time memorising them all, or just lesrn how to profile and be analytical and make informed optimisation decisions.
@Knuckles27617 сағат бұрын
But what about multi-threaded stuff? (Unity ECS, jobs) I didn't benchmark, but I guess caching would be more faster, the difference will increase.
@AhmedMohammed23Күн бұрын
my guy nick started with conquer online servers like me
@playitliveКүн бұрын
Same example but with record??
@NavhkrinКүн бұрын
As a game dev, no, not even Naughty Dog is going to care about a performance difference of 0.5ns. Even if you access static object 1000 times per frame at 1000fps that difference is 1ms per second, which means it will only slow down your game by about %0.001. Trust me, there is like a million other things you can optimise before you bother with optimizing access times of 0.5ns
@KabbinjКүн бұрын
"Benchmark it" he says, then proceeds to benchmark the wrong language 😂
@Tsunami14Күн бұрын
I think this is also where Nick is going, but this seems like such a pointless question. By definition, singletons and static classes will (at most) be instaniated once, so any performance difference would be negligible in the grand scheme of things.
@kinsondigital11 сағат бұрын
Just benchmark it for sure. Do not just take any bodies word for it! If you don't benchmark yourself, you will end up causing yourself problems down the road. You NEVER truly know what might be going on in any code path. I learned this as well when building Velaptor which is a 2D game dev framework. Save yourself the time and headache.
@johnathankrausrig9237Күн бұрын
you started in gameserver emulation huh? Does "Skidrow" Ring a bell? :D
@flogginga_dead_horse4022Күн бұрын
I first read this as "you simpletons need to" sleepy
@Yogs01180Күн бұрын
i understand the point here you're talking about singleton fine. but as un indee game dev i don't recommend using singletons and you should avoid them as far as you can and use SO instead as singeleton will create scene dependent scripts and it will be a nightmare to maintain the game. i recommend watching the channel of git ammend there is awesome talks about this topic and others.
@wdolek15 сағат бұрын
@nick I’m disappointed random number wasn’t 69 or 420 explicitly… 😅 Also, update your Rider plugins.
@darkjudicКүн бұрын
if or not to if, that is the question:)
@_samirdahal8 сағат бұрын
Yep, there are other things to worry about. 😆
@rauberhotzenplotz7722Күн бұрын
Perhaps i'm oversimplifying, but my singletons look like public sealed class Singleton { public static readonly Singleton Default = new(); }
@ethanr0xКүн бұрын
Not thread-safe.
@zoiobnuКүн бұрын
Please remove automatic translation.
@sealsharpКүн бұрын
This is nonsense. Benchmarking something that has a result in nanoseconds but in the real world contains reading a value from RAM has no value. Both benchmarks read from CPU cache, so it is only the method call overhead. And just to be sure i googled memory latency, and it is still around 13ns for modern RAM.
@ANdR3WISCOOL20 сағат бұрын
I don't like it, the random number should have returned a 69 or 420
@Panure4 сағат бұрын
Nick is really good looking
@JacobNaxКүн бұрын
Singletons are only used by junior developers because they lack the fundamental knowledge to do dependency injection which would negate the need to have a singleton. For me they are considered anti-pattern since they can create the following issues: 1. Anti-testing issue (Can't test code that uses singletons) 2. Global states (bad cache utilization for video games since the memory location is laid out everywhere) 3. Increased complexity which can lead to spaghetti 4. Cross dependency-initialization issues (Singleton accessing another singleton which i've seen it happen many times) Most of these issues if not all are usually just applicable to game code and you don't need to bother if you're just writing some small app that does something simple. Either way you can just do DI and avoid this anti-pattern pattern.
@S1lenc31991Күн бұрын
Singletons have nothing to do with Dependency Injection, DI does not negate the need for Singletons. There is an Extension Method on the Service Collection called "AddSingleton". This way, it is just handled by the DI-Framework. But yes, Singletons can be problematic, especially when used extensively...
@IingvarkaКүн бұрын
Don't agree with you. What if you need to have some state that is the same across whole application lifetime. Read from a file once for example That singleton from the video is barely used. Class is usually registered as singleton during DI and you can easy do testing where it is used.
@Sayuri998Күн бұрын
Funny thing you should mention DI frameworks. I do not use one, because I feel like they obfuscate code more than they help. Where did my instance come from? Where was my instance created? Tracking that through a DI framework whose internals you don't know, is a pain. I love DI, but I always do pure manual DI all the way. Regarding singletons, I really think it's an anti-pattern. There is no reason for it to exist in my opinion. If you need an instance and only one instance of a class, instantiate it once then inject it where it's needed. You control where it's created, you control the lifetime. No performance overhead, no "multi-second" surprises.
@ConnorZ9 сағат бұрын
This video is incorrect in many ways.. sorry Nick..
@nthnnnnnnnnn14 сағат бұрын
This is disinformation and noise. I'd expect better from you since you have some good content also. Also benchmarking this is quite silly, you can't benchmark every little minuscule detail. You need to have some basic knowledge so you can make intelligent decisions about simple stuff like this.
@SilentsoulsКүн бұрын
return _instance ??= new Manager(); is all you need.