.NET Research: How StackOverflow snippets slow down your code

In this post, I wanted to make some performance research of a StackOverflow answer for making a Generic object Copy extension method.

I wanted to make a function, that can make a new copy instance of an object. Why? Because currently, the .NET framewrok has no built in Copy function. Than, I found the answer below a question: Serialize the object, and deserialize it again. What a great answer: No need to maintain, or bugfix the code, NewtonsoftJSON is a mature library.

        public static T GetCopy<T>(this T obj)
        {
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
        }

Does this function will work?

Of course.

Is it a good practice?

Well, mmmmmmmmmmmaybe in some scenarios, but we have to think about it really carefully.
Are you developing an application, for yourself, and need this to copy 1 or 2 times during the programs lifetime? It could be great for you, no need to invest time for writing the Copy method for the large object, and on the performance side, your method will return about 100 ticks later.. Also, you don’t need to worry about maintaining the copy function when the object’s scheme is changed.

OMG, who is using it, when reflection is available too?

Trust me, it seems simpler than searching properties and getting their values at runtime by yourself. And that’s what motivates developers to use mess snippets

Enterprise CTRL+V

So, are you developing application for a company? Please don’t use codes only because they work from stackoverflow unless you really sure about what the snippet does.

In a company, organization, open source projects, you do not write the code for yourself, you are writing it to everyone else, except yourself. A project’s lifetime could be longer than you are on the project. And why is it a drawback? Because you have implemented the GetCopy function by calling JsonConvert inside of it. You know, that you should not use it in loops, or performance critical points of the app. But does your colleague do? Maybe he knows. But what about the 30 other descendant programmer? They will start to use your ugly GetCopy function on the most critic part of the app, and it will be slowly a mess, unless a great qualified person get’s rid of the mess.

Let’s do the research

I have created a very simple class, with some value properties in it.

        public class TheCopyClass
        {
            public string prop1 { get; set; }
            public int prop2 { get; set; }
            public double prop3 { get; set; }

            public TheCopyClass Copy()
            {

                return new TheCopyClass()
                {
                    prop1 = prop1,
                    prop2 = prop2,
                    prop3 = prop3,
                };
            }
        }

For 1000 times, I’ve created an instance of the TheCopyClass by calling the class’s Copy method, and the extensions GetCopy method.

Also, declared two 10000000 item long arrays of this class, and inspected the elapsed time to fill them up.

            TheCopyClass classToCopy = new TheCopyClass()
            {
                prop1 = "This is a string",
                prop2 = int.MaxValue,
                prop3 = double.MaxValue
            };

            List<long> instanceCreationWithMethod1TickResults = new List<long>();
            List<long> instanceCreationWithMethod2TickResults = new List<long>();
            List<long> arrayFillWithMethod1TickResults = new List<long>();
            List<long> arrayFillWithMethod2TickResults = new List<long>();

            for (int j = 0; j < 1000; j++)
            {
                Console.WriteLine($"------ Iteration : " + j);

                TheCopyClass[] method1 = new TheCopyClass[10000000];
                TheCopyClass[] method2 = new TheCopyClass[10000000];

                Stopwatch watch = new Stopwatch();

                watch.Start();
                TheCopyClass method1Instance = classToCopy.Copy();
                watch.Stop();

                Console.WriteLine($"Instance creation Method 1. Elapsed ticks: {watch.ElapsedTicks}");
                instanceCreationWithMethod1TickResults.Add(watch.ElapsedTicks);
                watch.Reset();

                watch.Start();
                TheCopyClass method2Instance = classToCopy.GetCopy();
                watch.Stop();

                Console.WriteLine($"Instance creation Method 2. Elapsed ticks: {watch.ElapsedTicks}");
                instanceCreationWithMethod2TickResults.Add(watch.ElapsedTicks);
                watch.Reset();

                watch.Start();
                for (int i = 0; i < 1000; i++)
                {
                    method1[i] = classToCopy.Copy();
                }
                watch.Stop();

                Console.WriteLine($"Array Method 1. Elapsed milisecs: {watch.ElapsedMilliseconds}, Elapsed ticks: {watch.ElapsedTicks}");
                arrayFillWithMethod1TickResults.Add(watch.ElapsedTicks);
                watch.Reset();

                watch.Start();
                for (int i = 0; i < 1000; i++)
                {
                    method2[i] = classToCopy.GetCopy();
                }
                watch.Stop();

                Console.WriteLine($"Array Method 2. Elapsed milisecs: {watch.ElapsedMilliseconds}, Elapsed ticks: {watch.ElapsedTicks}");
                arrayFillWithMethod2TickResults.Add(watch.ElapsedTicks);
            }

            Console.WriteLine("------------- RESULTS -------------");
            Console.WriteLine($"Method 1 Instance creation: Avg: {instanceCreationWithMethod1TickResults.Average()}");
            Console.WriteLine($"Method 2 Instance creation: Avg: {instanceCreationWithMethod2TickResults.Average()}");
            Console.WriteLine($"Method 1 array fill: Avg: {arrayFillWithMethod1TickResults.Average()}");
            Console.WriteLine($"Method 2 array fill: Avg: {arrayFillWithMethod2TickResults.Average()}");

The results

------------- RESULTS -------------
Method 1 Instance creation: Avg: 20,462
Method 2 Instance creation: Avg: 3640,179
Method 1 array fill: Avg: 478,025
Method 2 array fill: Avg: 125038,821

The extension method’s single instance creation is 178 times slower in average than calling the class’s Copy method, and when it comes to massive array filling, the 10000000 item array will be filled up 262x slower.

Szólj hozzá!

Ez az oldal az Akismet szolgáltatást használja a spam csökkentésére. Ismerje meg a hozzászólás adatainak feldolgozását .