Search Unity

Singletons Vs. Tags

Discussion in 'Scripting' started by _AB, Jun 29, 2015.

  1. _AB

    _AB

    Joined:
    Jun 1, 2015
    Posts:
    9
    Hello
    This post is just meant to be proof for a friend of mine, and I thought it would be wise to share it here so others won't make the same mistake.

    I had a friend of mine who told me that using GameObject.FindWithTag() is much faster and a more professional replacement to Singletons. I ran some tests with this:

    P.S: AudioManager is a singleton GameObject with an "Audio Manager" tag.

    Code (CSharp):
    1. public void Init() {
    2.  
    3.         const int max = 1000000;
    4.         var s1 = Stopwatch.StartNew();
    5.         for(int i = 0; i < max; i++) {
    6.  
    7.             AudioManager.Instance.Test(0);
    8.             AudioManager.Instance.Test(0);
    9.         }
    10.         s1.Stop();
    11.  
    12.         var s2 = Stopwatch.StartNew();
    13.         for(int i = 0; i < max; i++) {
    14.            
    15.             GameObject.FindWithTag("Audio Manager").GetComponent<AudioManager>().Test (0);
    16.             GameObject.FindWithTag("Audio Manager").GetComponent<AudioManager>().Test (0);
    17.         }
    18.         s2.Stop();
    19.  
    20.         var res1 = (double)(s1.Elapsed.TotalMilliseconds * 1000000) / max;
    21.         var res2 = (double)(s2.Elapsed.TotalMilliseconds * 1000000) / max;
    22.         UnityEngine.Debug.Log ("res1: " + res1.ToString("0.00 ns"));
    23.         UnityEngine.Debug.Log ("res2: " + res2.ToString("0.00 ns"));
    24.  
    25.     }
    The results came out like this:
    In the given test conditions, singletons were 10 times as fast.

    Singletons are FREAKIN' FANTASTIC, but has to be used wisely...

    For more info and alternative: check out these two sources:
    One
    Two
     
    boraygen likes this.
  2. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I always wonder how someone can find a string based method call professional. I would even use non string based methods if they were slower. If someone renames a tag, a game object or something else in a project, it shouldn't have any impact on the code.
     
    Korno and Deleted User like this.
  3. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    i have been rather partial to doing singletons like this.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    5. {
    6.     protected static T instance;
    7.  
    8.     public static T Instance
    9.     {
    10.         get
    11.         {
    12.             if (instance == null)
    13.             {
    14.                 instance = (T)FindObjectOfType<T>();
    15.                 if (instance == null)
    16.                 {
    17.                     Debug.LogError("An instance of " + typeof(T) +
    18.                         " is needed in the scene, but there is none.");
    19.                 }
    20.             }
    21.             return instance;
    22.         }
    23.     }
    24. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GameManager : Singleton<GameManager>
    5. {
    6.     private int myInt;
    7.  
    8.     public static void DoGMShit() {
    9.         Instance.myint = 4;
    10.     }
    11. }
    Lets me isolate all the singleton initialization code, while giving a easy way to access a instance publicly using Instance, and is cached statically to help performance and to prevent having to look for the instance every time.
     
    Last edited: Jun 29, 2015
    boraygen and _AB like this.
  4. YoungDeveloper

    YoungDeveloper

    Joined:
    Jun 28, 2013
    Posts:
    65
    Of course it's faster, Find single functions might loop thought all scene object in the worst case.
    While by singleton you access hard coded reference. There's even nothing to compare here to be honest.

    Doing it once and caching the reference doesn't sound that bad either. But I've seen code where
    find functions are used 20 times in an update. Personally i don't use any Unity Find fucntions, but create my own pools.
     
    Soraphis likes this.
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Right tool for the right job. You are comparing apples with oranges here. The job of a singleton is not the same as the job of a tag.

    There are also plenty of non performance factors to consider here. There are actually only a few cases where a singleton is the right solution.
     
    lordofduct likes this.
  6. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    This might be the most biased performance test I've ever seen.

    Compare them like you would use them in the real world:
    Code (csharp):
    1.  
    2.  
    3.   var s2 = Stopwatch.StartNew();
    4.   var audioManager = GameObject.FindWithTag("Audio Manager").GetComponent<AudioManager>();
    5.  
    6.   for(int i = 0; i < max; i++) {
    7.    audioManager.Test(0);
    8.    audioManager.Test(0);
    9.   }
    10.   s2.Stop();
    11.  
    Singletons are bad design and you should avoid them whenever possible to keep your codebase modular and reuseable.
     
    Kiwasi likes this.
  7. Brainswitch

    Brainswitch

    Joined:
    Apr 24, 2013
    Posts:
    270
    Agreed. I wish Unity had more built-in tools to deal with this (like auto-creating enums/constants for tags/layers with proper renaming support).

    I believe string-based search solutions for things like Tags and Layers (not to mention method calls, like in SendMessage) are bad design and prone to not so easy to spot errors.
     
    Soraphis likes this.
  8. _AB

    _AB

    Joined:
    Jun 1, 2015
    Posts:
    9
    Singletons are not bad design. Some people avoid them like the plague, but they are not bad. They are a viable solution to many problems (Audio, logging, file management, etc...).

    Correct me if I am wrong, but the general consensus agree that Singletons are bad when they encourage coupling, when they are used wrongly in multi-threading situations, and because they offer an "overkill" solution to a simple problem (Most of the time).

    But, if the developer used them sparingly and smartly, they wouldn't offer a problem. Personally, I'd prefer a decent observer and service locator pattern, but I would use a singleton for audio management, and as a "Director/HoldAllManagers" manner like this:

    Code (CSharp):
    1. Director.Instance.GetAtlasManager().CreateSprite("mySprite");
    P.S: The idea for the above came from Game Programming Patterns by Robert Nystrom.

    EDIT: One more question, please. I can understand that string-based call methods are not very optimal, but they are necessary for a messaging system, right ?? I am referring to the Advanced C# Messanger from the wiki.
     
    Last edited: Jun 30, 2015
  9. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    No, they are not required. They can be designed differently. There are several solutions for that. You may e.g. have a delegate for each kind of message, which automatically eliminates the need for strings.

    The very minimum one should do when using string based calls is to use constant strings that are defined globally and everyone can get the same one in order to avoid typos.
     
    _AB likes this.
  10. _AB

    _AB

    Joined:
    Jun 1, 2015
    Posts:
    9
    I did some research and found the "Type-Safe Enums" pattern which works great with what you said. Thanks for the tip. +1
     
  11. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    This

    Code (csharp):
    1.  
    2. AudioManager.Instance.Test(0);
    3.  
    is faster than this

    Code (csharp):
    1.  
    2. GameObject.FindWithTag("Audio Manager").GetComponent<AudioManager>().Test (0);
    3.  
    not because it's a singleton, but because that second line is a bazillion slow function calls just to get to the Test() function call.

    In the first case you have a reference pointed already to the AudioManager object (singleton or not), then calling the Test() function directly. In the second case you're calling several functions just to get a reference to the AudioManager object so you can call the Test() function which takes an eternity. This is why the first method is faster, it has nothing to do with it being a singleton. You could have an AudioManager array of many AudioManager objects and get the same results.

    This article I wrote some time ago might help shed a little light on function call overhead. This is geared toward math and physics in Unity, but the same principle applies.

    http://www.performancesimulations.c...ses-in-unitys-physics-or-any-math-heavy-code/
     
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This is a very good suggestion. And in general strings based methods should be avoided, especially if the strings are defined by the coder.

    There are some situations were stings are the only way to go though. Communicating between different systems using different frame works for example. Or communicating with scripts and code that was not available to the coder or compiler at the time of production of the code.
     
  13. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I agree. There are certainly situations in which it can't be avoided. In Unity that is e.g. required when a material modifies a shader property or in Mecanim it is required too. But also in those situations, it may be possible to check during the initialization whether the strings are valid to avoid issues with not frequently used options.
    Do you have an example for what you mean with different systems using different frame works? Do you mean something within Unity or something external?
     
  14. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I am not really a fan of this approach, as it has an unnecessary indirection. In most situations that I have faced, it wasn't necessary to have that indirection and I could directly work with whatever I needed. If you have to pass the enum to get what you want, you know anyways what you want, based on the enum and as such you can access it directly.
    Of course in Unity, you may configure something in the inspector where you specify an enum value. But that is often abused in my opinion. With that approach, we can get a situation where we pass an enum in order to get something back, but if there is nothing for this enum, we have a problem. I can also run into initialization problems, e.g. when someone makes a query for a certain enum, but the dictionary wasn't initialized yet.
    When I call the thing I want directly, there is the advantage of compile time warning. When I query something that doesn't exist, I get a compile time error. When I extend the enum with another entry, but forget to initialize the dictionary, there is no warning. If it is not properly tested, it can have consequences at some point in the future, which could often be avoided.
     
  15. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    just use what is best for the job, events and delagates are sometimes the key, sometimes its singletons. in situations where i cant avoid strings i will usually have static class full of string constants, so i can avoid typos. In the case of animations i will often just use hashes for state names, with static constants that refer to them.
     
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Well you described one in your post, communicating with shaders.

    It could also be communicating externally, like contacting a web service. Internet based applications depend on strings heavily because you never know what kind of system is on the receiving end. You don't know the word size they operate on, the word format, the OS, the processor type, nothing. You could be communicating with a water droplet based processor (http://www.engadget.com/2015/06/10/water-droplet-computer/).
     
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Communicating with a web browser from a web player is the example I come across most often.
     
  18. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Of course, web services are using strings. However, the communication is usually using e.g. Xml or Json. Those have been developed exactly to avoid issues with strings by providing a standard solution to make them better accessible.

    Yes, I missed that case.