C # performance optimization practices

Source: Internet
Author: User

Performance Optimization Principles

·Understanding requirements

One performance requirement of MultiRow is: "smooth scrolling under millions of data lines ." This goal has been taken into account throughout the development process of the MultiRow project.

·Understanding bottlenecks

 

99% of the performance consumption is caused by 1% of the Code. Most performance optimizations aim at these 1% bottleneck codes. The specific implementation is divided into two steps: "discovering bottlenecks" and "eliminating bottlenecks ".

·Avoid excessive

Performance optimization is costly. This cost is not only the workload of performance optimization, but also the extra maintenance costs caused by writing complex code for performance optimization, such as introducing new bugs, additional memory overhead. Performance Optimization often requires a trade-off between benefits and costs.

How to discover performance bottlenecks

The first step in performance optimization is to discover performance bottlenecks. The following are some practices for locating performance bottlenecks.

·How to Get memory consumption

The following code gets the memory consumption of an operation.

Long start = GC. getTotalMemory (true); // write the code to be tested for memory consumption here. For example, create a GcMultiRowvar gcMulitRow1 = new GcMultiRow (); GC. collect (); // ensure that all memory is recycled by GC. waitForFullGCComplete (); long end = GC. getTotalMemory (true); long useMemory = end-start;

 

·How to get time consumption

The following code obtains the time consumed by an operation.

System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();watch.Start();for (int i = 0; i < 1000; i++){gcMultiRow1.Sort();}watch.Stop();var useTime = (double)watch.ElapsedMilliseconds / 1000;

In order to get a more stable time consumption, an operation is executed 1000 times in a loop here, and the average value of time consumption is obtained to eliminate unstable data.

·ANTS Performance Profiler

ANTS Performance Profiler is a powerful Performance detection software. Skilled in using this tool, we can quickly and accurately locate code with performance problems. This is a paid software, and some hooks will be added to IL to record the time. Therefore, during analysis, the execution speed of the software will be slower than the actual operation, therefore, the obtained data is not accurate, and the performance of the program must be analyzed with other techniques.

·CodeReview

CodeReview is the final means to discover performance problems. CodeReview should pay as much attention to product performance bottlenecks as possible to ensure that this part of logic is executed as quickly as possible.

Performance Optimization Methods and Techniques

There are many solutions after locating performance problems. The following are some performance optimization techniques and practices.

·Optimize program structure

During the design, whether the product structure can meet the performance requirements should be considered. If performance problems are found later, adjusting the structure will bring about a lot of overhead.

For example:

GcMultiRow must support 1 million rows of data. If each row has 10 columns, 10 million cells are required, and each cell has many attributes. If no optimization is made, the memory overhead of A GcMultiRow software will be quite large when the data volume is large. GcMultiRow uses a hash table to store row data. Only modified rows are placed in the hash table, and most unmodified rows are directly replaced by templates. This achieves the purpose of saving memory.

Different from Winform, the WPF platform and Silverlight platform are implemented by combining Visual elements. The SpreadGrid for WPF product also supports millions of data records, but cannot allocate a View to each cell. Therefore, SpreadGrid uses VirtualizingPanel for painting. The idea is that each Visual is a Cell display module, which can be separated from the Cell data module. In this way, you only need to create a Visual for the displayed Cell. When a scroll occurs, some cells will be rolled out of the screen, and some cells will be rolled into the screen. In this case, let the Cell out of the screen and Visual separation, and then reuse this part of the Visual to the new Cell into the screen. In this loop, you only need several hundred Visual files to support many cells.

·Cache

Cache is the most commonly used method for performance optimization. It takes a long time to obtain data frequently and at the same time. If the cache optimization method is used, pay special attention to the synchronization of cached data: if the actual data changes, the cached data should be promptly cleared, make sure that no error data is used because of the cache.

Cache is used in many cases. The simplest case is to cache it to a Field or a temporary variable.

for(int i = 0; i < gcMultiRow.RowCount; i++){ // Do something; } 

The above code is normal, but if the number of GcMultiRow rows is large. When the value of the RowCount attribute is slow, you need to use the cache for performance optimization.

int rowCount = gcMultiRow.RowCount;for (int i = 0; i < rowCount; i++){// Do something;}

Using an object pool is also a common cache solution, which is a little more complex than using Field or temporary variables. For example, a large number of brushes and Pen are required to draw edges and backgrounds in MultiRow. These GDI objects must be created before each use and destroyed after use. The process of creation and destruction is relatively slow. GcMultiRow is used to create a GDIPool. Essentially, it is a Dictionary that uses color as the Key. Therefore, you only need to create the image for the first time, and then use the previously created image directly.

The following is the GDIPool code:

public static class GDIPool { Dictionary<Color, Brush > _cacheBrush = new Dictionary<Color, Brush>(); Dictionary<Color, Pen> _cachePen = new Dictionary<Color, Pen>(); public static Pen GetPen(Color color) { Pen pen; if_cachePen.TryGetValue(color, out pen)) { return pen; } pen = new Pen(color); _cachePen.Add(color, pen); return pen; } }

·Lazy Construction

Most of the time, not all scenarios need to be used to create objects that take a long time. In this case, the lazy construction method can effectively improve the Startup Performance of the program.

For example, object A needs to create object B internally. The construction time of object B is relatively long. General Practice:

public class A{public B _b = new B();}

In general, because object A needs to be constructed while object B is constructed, the construction speed of object A is also slowed down.

Optimization practices:

public class A{private B _b;public B BProperty{get{if(_b == null){_b = new B();}return _b;}}}

After optimization, you do not need to create B objects when constructing A, which effectively improves the construction performance of.

·Optimization Algorithm

The optimization algorithm can effectively improve the performance of specific operations. When using an algorithm, you should understand the applicability, best condition, and worst condition of the algorithm. Taking GcMultiRow as an example, the original MultiRow sorting algorithm uses the classic quick sorting algorithm. It seems that there is no problem. However, for table software, you often sort ordered tables, such as switching between order and reverse order. The worst case of a classic fast sorting algorithm is the basic order. Therefore, the classic fast sorting algorithm is not suitable for MultiRow.

The improved quick sorting algorithm uses three dots to replace the algorithm of a midpoint in the classic fast sorting. The median value is selected from the three centers for each exchange. In this way, disorder and basic order are not the worst cases of this algorithm, thus optimizing the performance.

·Correct use of existing data structures

The. NET framework Platform we work on now has many ready-made data structures. We should understand these data structures to improve the performance of our programs.

For example:

1. String addition operator and StringBuilder: String operations are one of the basic operations we often encounter. We often write this code string str = str1 + str2. When there are few strings to operate on, this operation is fine. However, if a large number of operations (such as Save/Load of text files and Render of Asp.net) are performed, this will cause serious performance problems. In this case, we should use StringBuilder to replace the string addition operation.

2. Dictionary and List: Dictionary and List are the two most common collection classes. Selecting the correct collection class can greatly improve the program performance. To make the right choice, we should have a better understanding of the performance of various operations of Dictionary and List. The following table roughly lists the performance comparison of the two data structures.

Operation

List

Dictionary

Index

Fast

Slow

Find (Contains)

Slow

Fast

Add

Fast

Slow

Insert

Slow

Fast

Remove

Slow

Fast

 

3. TryGetValue: the following code compares the value of a Dictionary:

if(_dic.ContainKey("Key"){return _dic["Key"];}      

When a large number of values are required, this method may cause performance problems. The optimization method is as follows:

object value;if(_dic.TryGetValue("Key", out value)){return value;}

The latter method is twice as good as the previous one.

4. select an appropriate Key for a Dictionary. The performance of the value of the Dictionary depends on the performance of the Equals and GetHashCode methods of the Key object. If possible, use Int for the best Key performance. If a custom Class is used as the Key, it is best to ensure the following two points: 1. The GetHashCode repetition rate of different objects is low. 2. The GetHashCode and Equals methods are simple and efficient.

5. List Sort and BinarySearch have good performance. If they can meet functional requirements, we recommend that you use them directly.

List<int> list = new List<int>{3, 10, 15};

 

List. BinarySearch (10); // for an existing value, the result is 1.

 

List. BinarySearch (8); // for nonexistent values, a negative number is used to represent the position,

 

// For example, if you search for 8, the result is-2. If you search for 0, the result is-1. If you search for 100, the result is-4.

 

·Improves response time asynchronously.

1.Multithreading

Some operations take a long time. In the process of processing, if the user loses the response during the operation, the user experience is poor. Multithreading technology can solve this problem. For example, a computing engine similar to Excel needs to initialize all function definitions during construction. Because there are many functions, the initialization time will be relatively long. If multithreading is used, initialization of the function definition in the working thread will not affect the UI thread to quickly respond to other operations of the user.

The Code is as follows:

public CalcParser(){ if (_functions == null)  {   lock (_obtainFunctionLocker)   {    if (_functions == null)    {      System.Threading.ThreadPool.QueueUserWorkItem((s) =>       {       if (_functions == null)        {          lock (_obtainFunctionLocker)          {            if (_functions == null)            {              _functions = EnsureFunctions();             }           }         }         });        }       }      }     } 

The slow operation here is the EnsureFunctions function, which is executed in another thread and does not affect the response of the main thread. Of course, multithreading is a relatively difficult solution, and cross-thread access and deadlock issues need to be fully considered.

2.Latency

When GcMultiRow is used to implement AutoFilter, a scheme similar to delayed execution is used to increase the response speed. The AutoFilter function is used to update and filter results based on user input. When the data volume is large, it takes a long time to filter data at a time. This results in poor user input and poor user experience. Multithreading is a good solution, but it increases the complexity of the program. The MultiRow solution is to wait 0.3 seconds when receiving the input message from the user's keyboard instead of starting Filter immediately. If the user continuously inputs the data, the system will receive the keyboard message again within 0.3 seconds, discard the previous task, and wait for another 0.3 seconds until there is no new Keyboard Message for 0.3 consecutive seconds, and then trigger the Filter. In this way, a smooth user experience is achieved.

3. Application. IdleEvent

In GcMultiRow Designer, the Disable/Enable status of the buttons on the ToolBar is often refreshed based on the current status. A refresh takes a long time. This affects the smoothness of user input. GcMultiRow is optimized by using the system Application. Idle event to process the refresh logic only when the system is Idle. When you receive this event, the user has already completed continuous input, and you can easily refresh the button status.

4. Refresh, BeginInvoke

The Platform also provides some asynchronous solutions. For example, when a Refresh method is called under WinForm to trigger a redraw of a region, the Refresh method does not cause immediate re-painting. Instead, the Invalidate tag is set to trigger asynchronous Refresh. In control development, this technique can effectively improve product performance and simplify implementation complexity.

The Control. BeginInvoke method can be used to trigger asynchronous custom behaviors.

·Progress bar to improve user experience

Sometimes, none of the above solutions can quickly respond to user operations. Progress bars, pictures that have been circled, and prompt text (such as "Your operations may take a long time, please be patient") can all effectively improve the user experience, it can be considered as the final solution.

Author profile:

Hu Sen is a software engineer and Project Manager of PowerTools. I have been focusing on the design and development of. NET UI controls for a long time. It is committed to providing powerful, efficient, and easy-to-use control products for a wide range of. NET developers.

Thank you for reviewing this article.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.