Monday 15 April 2013

CultureInfo : le killer de performance ( Franglais )

In this post, je démontre qu'une application peut rapidement perdre en performance, allant jusqu'à 1000% du temps d'execution, par une utilisation abusive du constructeur de la classe CultureInfo.
Study case :

 Just copy the code below in the main method of a console app and then execute it

            DateTime today = DateTime.Now;
            //Feed the list by dummy data
            List<DateTime> tenDaysAgo = new List<DateTime>();
            for (int i = 0; i < 10000; i++)
            {
                tenDaysAgo.Add(today.AddDays(-i));
            }
           
            //Start the stopwatch
            Stopwatch sw = new Stopwatch();
            sw.Start();
            foreach (var item in tenDaysAgo)
            {
                //Define the currentCulture
                IFormatProvider currentCulture = new CultureInfo("FR");
                //Try to parse with the currentCulture
                DateTime.TryParse(item.ToString(), currentCulture, DateTimeStyles.None, out dateOut);          
            }
            sw.Stop();
            Console.WriteLine("Ellapsed time = " + sw.ElapsedMilliseconds + " ms");
            Console.ReadLine();



 It took about 20000 ms to execute on my laptop ( Dell core i7 Q, 16Go RAM ).

 As you've seen the program performs very poorly
The issue comes from this instruction :
          IFormatProvider currentCulture = new CultureInfo("FR");
 inside the foreach loop. It takes about 3ms second to create an instance of CultureInfo.

Solution :

DateTime today = DateTime.Now;
            //Feed the list by dummy data
            List<DateTime> tenDaysAgo = new List<DateTime>();
            for (int i = 0; i < 10000; i++)
            {
                tenDaysAgo.Add(today.AddDays(-i));
            }
           
            //Start the stopwatch
            IFormatProvider currentCulture = new CultureInfo("FR");
            Stopwatch sw = new Stopwatch();
            sw.Start();
            foreach (var item in tenDaysAgo)
            {
                //Define the currentCulture
               
                //Try to parse with the currentCulture
                DateTime.TryParse(item.ToString(), currentCulture, DateTimeStyles.None, out dateOut);          
            }
            sw.Stop();
            Console.WriteLine("Ellapsed time = " + sw.ElapsedMilliseconds + " ms");
            Console.ReadLine(); 
 


 The above code does the same thing but takes just 77 ms to execute. 

Conclusion
 En général, toujours éviter de faire des constructions d'objets à l'intérieur d'une boucle. Cela peut engendrer une perte de performance énorme à partir d'un certain volume de données.

 
  

No comments:

Post a Comment