10 simple ways to improve program running efficiency

Source: Internet
Author: User
For every programmer, the running efficiency of the program is a matter worth attention and efforts. However, optimization of program performance is also complicated and requires a lot of knowledge. However, not every programmer has such knowledge, and there are few books on how to optimize programs to improve program running efficiency. However, this does not mean that we can ignore the program running efficiency. The following describes some simple and practical methods that I have accumulated to improve the program running efficiency. I hope this will help you. Note: Take the C/C ++ program as an example. Reduce the value transfer as much as possible, and use references to transmit parameters. As for the reason, it is clear that if the parameter is a custom type in Int or other languages, the performance may not be significantly affected, but if the parameter is a class object, the efficiency is self-evident. For example, if a function is used to determine whether two strings are equal, its declaration is as follows: bool compare (string S1, string S2) bool compare (string * S1, string * S2) bool compare (string & S1, string & S2) bool compare (const string & S1, const string & S2). If the first function (value passing) is used ), when passing parameters and returning functions, you need to call the string constructor and destructor twice (that is, four more functions are called ), the other three functions (pointer passing and reference passing) do not need to call these four functions. Because neither pointer nor reference creates a new object. If the overhead of constructing an object and destructing an object is huge, the efficiency will be affected. However, in the eyes of many people, pointers are a nightmare. Using pointers means errors, so use references! It is as convenient and intuitive as using normal value transfer, and has the efficiency and capability of pointer transfer. Because a reference is a variable alias and its operation is equivalent to an actual object operation, when you are sure that your function does not or does not need a variable parameter value, just add a const before the declaration, just like the last function declaration. A const can also be used to reference constants. Without the const modifier, constants cannot be referenced. 2. After reading the efficiency issues derived from ++ I and I ++, you may think that it is not just to call four more functions, you may not care about this. The following example will surprise you. As for the difference between the prefix and postfix of integer variables, it is clear to everyone. However, here I want to talk about the operator overloading of the C ++ class, in order to be consistent with the usage of integer variables, when the operator ++ is overloaded in C ++, both the prefix and the suffix are overloaded. You may say that you do not load the ++ operator in the code, but do you dare to say that you have never used the ++ operator overload of the class? You have always used the iterator class! Maybe you still don't know what I'm talking about. Let's take a look at the example below. It's an internal iterator I wrote for the linked list. _ Singlelist: iterator & _ singlelist: iterator: Operator ++ () // Add {pnote = pnote-> pnext; return * This;} _ singlelist :: iterator _ singlelist: iterator: Operator ++ (INT) // Add {iterator TMP (* This); pnote = pnote-> pnext; return TMP ;} you can see from the implementation method of the add-on that the object uses itself to create a temporary object (a copy of its own function call), then changes its status, and returns this temporary object, the implementation method of the prefix directly changes its internal status and returns its own reference. From the first point of view, we can know that the copy constructor will be called when the post-added implementation is implemented, and the Destructor will be called when the function is returned. Because the pre-added implementation method directly changes the internal state of the object, and return your reference. No new object is created from the beginning to the end, so the constructor and destructor will not be called. Even worse, the iterator is usually used to traverse containers. It is mostly used in loops. Imagine that your linked list has 100 elements and uses the following two methods to traverse them: for (_ singlelist: iterator it = List. begin (); it! = List. End (); ++ it) {// do something} For (_ singlelist: iterator it = List. Begin (); it! = List. end (); It ++) {// do something} if you are in bad habits and write the second form, unfortunately, to do the same thing, it is because of the difference between a prefix and a postfix that you need to call more than 200 functions. The impact on efficiency cannot be ignored. Iii. Loop-related discussion 1 (loop definition or out-of-loop definition object) See the following two sections of code: Code 1: classtest CT; For (INT I = 0; I <100; ++ I) {Ct = A; // do something} Code 2: For (INT I = 0; I <100; ++ I) {classtest Ct = A; // do something} Which code segment do you think is more efficient? Code 1 is Code 2 a scientist? In this case, it is not clear which code segment is more efficient, or is determined by the classtest class. The analysis is as follows: for code 1: the classtest constructor needs to be called once, and the value assignment operator (operator =) is used 100 times. For Code 2, the constructor needs to be used (copied) for 100 times, and the Destructor needs to be used for 100 times. If the overhead of calling the value assignment operation function is less than the total overhead of calling the constructor and destructor, the first method is more efficient; otherwise, the second method is more efficient. Iv. Loop-triggered discussion 2 (avoid excessive loops) Now let's take a look at the following two sections of code: Code 1: For (INT I = 0; I <n; ++ I) {fun1 (); fun2 ();} Code 2: For (INT I = 0; I <n; ++ I) {fun1 ();} for (INT I = 0; I <n; ++ I) {fun2 () ;}note: Here fun1 () and fun2 () are not associated, that is, the results of the two code segments are the same. At the code level, it seems that code 1 is more efficient, because after all, code 1 has n less self-addition operations and judgments, after all, auto-increment operations and judgments take time. But is it true? This depends on the scale (or complexity) of the fun1 and fun2 functions. If the code statements of these functions are few, code 1 is more efficient, however, if there are many fun1 and fun2 statements and the scale is large, code 2 runs more efficiently than Code 1. Maybe you don't understand why it is, or why it is based on computer hardware. Because the CPU can only read data from the memory, and the CPU computing speed is much higher than the memory, in order to improve the program running speed, effectively use the CPU capability, there is a cache memory between the memory and the CPU, and its speed is close to that of the CPU. The data in the cache is loaded from the memory. This process requires access to the memory, which is slow. Here we will talk about the design principle of cache, that is, time locality and space locality. Time locality means that if a storage unit is accessed, it may soon be accessed again because the program has a loop. Spatial locality means that if a storage unit is accessed, the adjacent units of the unit may be accessed quickly, because most of the commands in the program are stored sequentially and executed sequentially, data is also clustered in the form of vectors, arrays, trees, and tables. You may already understand the cause. That's it! If fun1 and fun2 have a large amount of code, for example, if they both exceed the cache capacity, the cache cannot be fully utilized in code 1 (known from temporal locality and spatial locality ), because the content in the cache should be kicked out once every loop, and the code instructions and data of another function should be loaded from the memory again, while Code 2 makes better use of the cache, using two loop statements, almost all the data used by each loop has been loaded into the cache. Each loop can read and write data from the cache, with less memory access and faster speed, theoretically, you only need to completely kick out the data of fun1 once. 5. Local variables vs static variables many people think that when using local variables, they will allocate storage units in the memory, and static variables will exist in the memory at the beginning of the program, so the efficiency of using static variables should be higher than that of local variables. In fact, this is a misunderstanding. The efficiency of using local variables is higher than that of using static variables. This is because local variables exist in the stack, and the allocation of space is only a modification to the content of the ESP register (even if a group of local variables are defined ). The biggest benefit of local variables in the stack is that the function can reuse the memory. When a function call is completed, it exits the program stack and the memory space is recycled, when a new function is called, local variables can use the same address again. When a piece of data is read and written repeatedly, the data will be stored in the CPU cache, And the access speed is very fast. Static variables do not exist in the stack. Static variables are inefficient. 6. Avoid using multi-inheritance in C ++ and support multi-inheritance. That is, a subclass can have multiple parent classes. The book tells us about the complexity and difficulties of Multi-inheritance, and warns us not to use multi-inheritance easily. In fact, multi-inheritance not only makes the program and code more complex, but also affects the running efficiency of the program. This is because in C ++, each object has a this pointer pointing to the object itself, and the use of member variables in C ++ classes is calculated by the address and offset of this, in the case of multiple inheritance, this calculation will make the variables more complex, thus reducing the program running efficiency. To solve the ambiguity, the multi-inheritance of the virtual base class has a more serious impact on efficiency, because its inheritance relationship is more complex and the parent class relationship of the member variable is more complex.
7. The function of using dynamic_castdynamic_cast as few as possible is to convert the pointer or referenced type. The conversion of dynamic_cast requires a certain relationship between the target type and the source object: inheritance relationship.
To implement pointer conversion from a subclass to a base class, in fact, this type of conversion is very inefficient and has a great impact on the program performance. It cannot be used in large quantities. The more complex the inheritance relationship is, the deeper the hierarchy, the larger the conversion time overhead is. In the program, we should try to reduce the usage.
8. Reduce Division operations whether integer or floating-point number operations, division is a slow operation instruction. Division in computers is complicated. To reduce the number of Division operations, we will introduce some simple methods to improve efficiency: 1. Convert division into multiplication through mathematical methods, such as if (A> B/C ), if A, B, and C are all positive numbers, they can be written as if (A * C> B) 2. There is room for Compiler optimization, for example, if you want to perform an int-type N/8 operation, writing (unsigned) N/8 is conducive to compiler optimization. To optimize the compiler, the divisor must be a constant, which can be done by modifying a variable with Const.
9. Declare a small-granularity function as an inline function. As we know, calling a function requires protecting the field, allocating memory for local variables, and restoring the field overhead after the function is completed, the Inline Function Directly writes its code to the calling function. Therefore, the overhead is not required, but the source code length of the Program increases.
Therefore, for small-granularity functions, the following maxfunctions can improve program efficiency because they do not need to call the overhead of common functions. Int max (int A, int B) {return A> B? A: B;
}
10. Multi-Purpose direct initialization corresponds to direct initialization. What is direct initialization? What is replication initialization? For example, classtest CT1; classtest CT2 (CT1); // initialize classtest ct3 = CT1 directly; // copy the initialization
So what is the difference between direct initialization and replication initialization? Direct Initialization is to construct another object directly with one object. For example, CT1 is used to construct CT2. Copy Initialization is to first construct an object and then copy another object value to this object, for example, first construct an object ct3, and then copy the value of the member variable in CT1 to ct3. From here, we can see that direct Initialization is more efficient, and direct Initialization is a benefit, objects that cannot be copied, such as stream objects, cannot be initialized with a value assignment. They can only be initialized directly. Maybe I'm not quite clear about it, so let's refer to the classic!
The following is the original example of primer: "when used for class type objects, the initialization replication form and direct form are different: the direct initialization directly calls the constructor that matches the real parameter, replication constructor is always called during replication initialization. Replication initialization first creates a temporary object using the specified constructor, and then copies the temporary object to the object being created using the replication constructor. "There is another section saying that, "There are usually differences between direct initialization and replication initialization only in low-level optimization. However, there are essential differences between types that do not support replication or use non-explicit constructor:
Ifstream file1 ("FILENAME"): // OK: Direct Initialization
Ifstream file2 = "FILENAME"; // error: copy constructor is private
"NOTE: If you have any questions about direct initialization and replication initialization, read another article I wrote: A major misunderstanding of C ++-the difference between direct initialization and replication Initialization is explained in depth, which contains detailed explanations about direct initialization and replication initialization.
Supplement: here is just a little bit of advice. Although I have said so much, I still want to say that we should avoid unnecessary optimization and immature optimization, immature optimization is the source of errors, because the compiler will do a lot of optimization you don't know.
In the future, we will find some simple ways to improve the running efficiency. We will continue to add ......

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.