转 c#性能优化秘密

原文:http://www.dotnetperls.com/optimization

Generally, using the simplest features of the language provides the best performance. For example, using the for-loop and avoiding parameters and return values is typically fastest. We balance these performance goals with readability.

Further:It is best to focus on the "hot paths" in your program for optimizations. Don‘t emphasize code that is rarely run.

Benchmark.
At all levels of performance optimization, you should be taking
measurements on the changes you make to methods. You can do this with
the .NET Framework methods available in the Stopwatch type.Stopwatch

Tip:It often pays to create console programs where the methods are benchmarked repeatedly on data as it changes.

Benchmark

Note:You should always avoid regressing performance unless there is a clear reason to do so.

Static methods.
Non-inlined instance methods are always slower than non-inlined static
methods. To call an instance method, the instance reference must be
resolved, to determine what method to call. Static methods do not use an
instance reference.

If you look at the intermediate language, you will see that static methods can be invoked with fewer instructions. You can see an experiment based on the callvirt and call instructions on this site.IL: callvirt
Arguments.
When you call any method that was not inlined, the runtime will
actually physically copy the variables you pass as arguments to the
formal parameter slot memory in the called method. This causes stack
memory operations.

Therefore:It is faster to minimize arguments, and even use constants in the called methods instead of passing them arguments.

Locals.
When you call a method in your C# program, the runtime allocates a
separate memory region to store all the local variable slots. This
memory is allocated on the stack even if you do not access the variables
in the function call.

Tip:You can call methods faster if they have fewer variables in them. Sometimes we can reuse the same variable.

One way
to do this is to isolate rarely used parts of methods in separate
methods. This makes the fast path in the called method more efficient,
which can have a significant performance gain.Arithmetic Optimization

Also:Often you can use a local variable to copy in a field. Then you can avoid accessing the field—by only changing the local.

Local Variable Field
Constants.
Constants are not assigned a memory region, but are instead considered
values. Therefore, you can never assign a constant, but loading the
constant into memory is more efficient. It is injected directly into the
instruction stream.

And:This eliminates any memory accesses outside of the memory, improving locality of reference.

ReadonlyConst
Static fields.
Static fields are faster than instance fields, for the same reason that
static methods are faster than instance methods. When you load a static
field into memory, you do not need the runtime to resolve the instance
expression.

Loading an instance field must have the object instance first resolved. Even in an object instance, loading a static field is faster because no instance expression instruction is ever used.Static Field
Inline.
Until .NET 4.5, the C# language had no ability to suggest a method be
inlined into its enclosing method call spots. And the .NET Framework is
often conservative. It will not inline medium-sized or large methods.

However:You can manually paste a method body into its call spot. Typically, this improves performance in micro-benchmarks.

Also:It is easy to do. But it will make code harder to modify. It is only suggested for a few critical spots in programs.

Inline Optimization

Tip:In .NET 4.5, the AggressiveInlining enum was introduced. This tells the compiler to inline if possible.

AggressiveInlining
Switch.
You will find that the switch statement compiles in a different way
than if-statements typically do. For example, if you use a switch on an
int, you will often get jump statements, which are similar to a computed
goto mechanism.

Note:Using jump tables makes switches much faster than some if-statements. Also, using a char switch on a string is fast.

If vs. SwitchSwitch
Flatten arrays.
Using two-dimensional arrays is relatively slow. You can explicitly
create a one-dimensional array and access it through arithmetic that
supposes it is a two-dimensional array. This is sometimes called
flattening an array.

Then:You must use multiplication and addition to acquire the correct element address. This optimization often improves performance.

Flatten Array
Jagged arrays.
Flattened arrays are typically most efficient. But they are
impractical. You can use jagged arrays to improve the lookup
performance. The .NET Framework enables faster accesses to jagged arrays
than to 2D arrays.Jagged Arrays

Caution:Jagged arrays may cause slower garbage collections—each jagged array element is treated separately by the garbage collector.

StringBuilder.
If you are doing significant appending of strings using the C#
language, the StringBuilder type can improve performance. This is
because the string type is immutable and can not be changed without
reallocating the entire object.
Sometimes, using
strings instead of StringBuilder for concatenations is faster. This is
typically the case when using small strings or doing infrequent appends.
With most loops, StringBuilder is the better choice.StringBuilderStringBuilder Optimization
Char arrays.
Using char arrays is sometimes the fastest way to build up a string.
Typically, we combine char arrays with for-loops and character testing
expressions. This logic is more painful to develop, but the time savings
can be significant.Char Array
Byte arrays.
In the C# language, the smallest unit of addressable storage is the
byte type. You can store ASCII characters in a single byte, as well as
small numbers. If you can store your data in an array of bytes, this
allows you to save memory.Byte Array
For example,
an array of characters or a string uses two bytes per character. An
array of bytes can represent that data in one byte per character. This
results in about half the total memory usage.ASCII Strings
Arrays.
We have many options for collections, such as the List or ArrayList.
These types are convenient and should be used when necessary. But it is
always more efficient to use a simple array if this is possible.

Note:Complex collections such as List and Dictionary are actually composed of internal arrays.

And:They
add logic to avoid the burden of managing the array size on each use.
But if you do not need this logic, an array is faster.

Arrays
Capacity.
For collections, you can use an optional capacity argument to influence
the initial buffer sizes. It is best to pass a reasonable parameter
when creating a Dictionary or List. This avoids many allocations when
adding elements.Capacity
Rewrite loops.
You can rewrite loops to improve performance. The foreach-loop has good
performance in many cases. But it is best to use the for-loop in all
performance-critical sections when possible.

Note:For-loops sometimes have better raw performance. And you can often reuse the index variable to optimize elsewhere.

Typically,
the while-loop, the for-loop and the do-while loop have the best
performance. Also, it is sometimes beneficial—and sometimes harmful—to
"hoist" the maximum loop variable outside of the for-loop statement.For vs. Foreach
Structs. It is typically best to entirely avoid

structs. If you use structs, you must avoid passing the struct as a parameter to methods. Otherwise, performance may degrade to worse than using a class type.

Note:In the .NET Framework, structs are copied in their entirety on each function call or return value.

Structs
can improve the performance of the garbage collector by reducing the
number of distinct objects. Also, you can sometimes use separate arrays
instead of arrays of structs, which can improve performance further.Struct
Lookup tables.
While switch statements or hashtables can provide good performance,
using a lookup table is frequently the optimal choice. Instead of
testing each character using logic to lowercase, you can translate it
through a lookup table.Char Lookup Table
Also,
the lookup table can be implemented as a character array. Another
example is that you can implement the ROT13 algorithm with a lookup
table, improving performance by more than two times.ROT13
Char argument.
Often, you may need to pass a single character to a method as an
argument. For example, the StringBuilder type allows you to append a
single char. The Response.Write method also allows you to write a single
char.Response.Write

Note:It is more efficient to pass a char instead of a single-char string. We benchmark and show this optimization.

Tip:The char is a value type, and is represented by two bytes, while a string is a reference type and requires over 20 bytes.

StringBuilder Data Types
ToString.
It is poor programming to use the ToString method when it is not
needed. Sometimes, developers will call ToString on a character in a
string, and then test it against a single-character string literal. This
is inefficient.

Instead:Use a character testing expression with two chars. Please reference the specific article on this topic for more details.

String For-Loop

Caution:This mistake sometimes results in code that is ten times slower than the correct approach.

Int string cache.
Many C# programs use the ToString method on integer values frequently.
This requires an allocation on the managed heap for the new string. This
will cause the next garbage collection to become slower.

Tip:You can use a lookup table cache to optimize common cases for the integer ToString operation.

And:This site demonstrates how this lookup table can make the ToString method thirty times faster.

ToString Optimization
IL Disassembler.
For .NET development, open your methods with the IL Disassembler tool
provided by Microsoft. This is a free tool and it provides an interface
to view the MSIL (Microsoft Intermediate Language) output of compiled
Release executables.

Tip:It is sometimes useful to save copies of the intermediate language as you make changes, or to even count instructions.

IL Disassembler
Avoid sorting.
Often, you can avoid performing a sort operation on an array or string
by testing whether the input string or array is already sorted.
Sometimes this makes a big performance improvement. In other cases, this
slows down programs.Alphabetize String
String conversions.
You can actually avoid many string-based conversions. For example, you
may need to ensure that a string is lowercased. If the string is already
lowercase, you can avoid allocating a new string.

However:The Framework ToLower method will not avoid this. You must manually test to see if no lowercasing is necessary.

char.IsLower
Avoid Path.
The Path methods in the System.IO namespace are somewhat slow for many
applications. Sometimes they can cause unnecessary allocations to occur,
copying strings more than once. We can avoid them with character-based
algorithms.Path, Optimization
List Clear.
Avoiding allocations is sometimes (but not always) faster. In some
programs, you can call Clear on a Dictionary to avoid re-creating a new
Dictionary. But in my testing, calling Clear on a List is slow.Clear
Instead,
just re-creating the List is faster. This is because the garbage
collector is more optimized for eliminating old data than the method.
This is not always the case. Experimentation and benchmarking is needed.
Hash.
It is important that you use hashtables in your programs when
appropriate. The Dictionary collection in the .NET Framework is not
optimal in many cases, but provides good performance in many different
situations.Dictionary

Tip:Knowing every detail of the hashtable type, in whatever language you are using, is nearly always a performance advantage.

Learn.
The site you are reading contains a multitude of optimization
experiments, often proven with benchmarks that provide times in
nanoseconds per method call. Resources such as this site are invaluable
for certain tasks in programming.

Note:Before Dot Net Perls came about, no site had this information on optimization. We should learn from each other.

Compiler theory.
Experimentation such as benchmarking and analyzing instructions
generated can result in excellent program performance. But without
understanding the core theories of compilers you may be lacking
knowledge about program performance.

However:Compiler theory involves advanced mathematics and can be dense to start with.

Compiler
My observation
is that few application developers have a significant knowledge of
compiler theory. This topic may be more suitable to academic computer
scientists and not rapid application development programmers.

Tip:You too can slay the dragon with syntax directed translation. The compiler is mightier than the sword.

Temporal locality.
Another way you can optimize a program significantly is by rearranging
it to increase temporal locality. This means that methods that act on a
certain part of memory (such as the hard disk) are run at all once.Temporal Locality
Undecidable.
The term "optimization" is a misnomer in computer science. A program
can never be truly optimized. Because compiler theory is undecidable, a
program can never be proven to be optimally efficient. Perhaps another
approach is faster.

However:One way we improve the situation is by extensively testing. Processors change. Theory only gets us so far.

Secrets.
There are many pages on this website that are focused on optimization
tips. These pages are listed below. Most of them rewrite a certain
pattern of code to something arguably more efficient.Array OptimizationChar LowercaseDecrement OptimizationDictionary OptimizationException Optimizationint.Parse OptimizationInteger AppendMask OptimizationParameter OptimizationReplace OptimizationToString Formats

Tip:Please be aware some of these optimizations result in code that is less maintainable. Not all secrets are useful ones.

Research.
I found many optimization tips (for various languages) in Code
Complete. I recommend this book for some tips. Some of the strategies
may not be useful in managed languages like C#, but many are still
relevant.

Use a high-quality design. Make the program right. Make it
modular and easily modifiable so that it‘s easy to work on later. When
it‘s complete and correct, check the performance. If the program
lumbers, make it fast and small. Don‘t optimize until you know you need
to.

Code Complete
Summary.
There are many optimizations you can make at the level of statements
and methods. External performance factors (including hardware) are more
significant for many programs. But these tips can help in a significant
way.

时间: 2024-11-05 21:38:23

转 c#性能优化秘密的相关文章

Android性能优化系列之apk瘦身

Android性能优化系列之布局优化 Android性能优化系列之内存优化 为什么APK要瘦身.APK越大,在下载安装过程中,他们耗费的流量会越多,安装等待时间也会越长:对于产品本身,意味着下载转化率会越低(因为竞品中,用户有更多机会选择那个体验最好,功能最多,性能最好,包最小的),所以apk的瘦身优化也很重要,本篇博客将讲述apk瘦身的相关内容. 包体分析 在Android Studio工具栏里,打开build–>Analyze APK, 选择要分析的APK包 可以看到占用空间的主要是代码.图

web前端9大性能优化方案汇总

网页的性能问题是产品开发过程中的一个重要的环节,在产品成功地把功能实现后,性能能好与坏就直接影响了用户体验,以至于影响了产品的成败! 作为web前端开发者,对前端部分进行性能上的优化,是责无旁贷,刻不容缓的工作.下面简介一下9种性能优化方案. 一.罪魁祸首是http请求 一般网页,80%的响应时间花在下载网页内容(images, stylesheets, javascripts, scripts, flash等).减少请求次数是缩短响应时间的关键!可以通过简化页面设计来减少请求次数,但页面内容较

Java性能优化的50个细节

在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身.养成良好的编码习惯非常重要,能够显著地提升程序性能. 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控制资源的并发访问: 第二,控制实例的产生,以达到节约资源的目的: 第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信. 2. 尽量避免随意使

iOS开发——项目实战总结&UITableView性能优化与卡顿问题

UITableView性能优化与卡顿问题 1.最常用的就是cell的重用, 注册重用标识符 如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell 如果有很多数据的时候,就会堆积很多cell.如果重用cell,为cell创建一个ID 每当需要显示cell 的时候,都会先去缓冲池中寻找可循环利用的cell,如果没有再重新创建cell 2.避免cell的重新布局 cell的布局填充等操作 比较耗时,一般创建时就布局好 如可以将cell单独放到一个自定义类,初始化时就布局好

Java性能优化之JVM GC(垃圾回收机制)

Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当stop-the-world 发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成.GC优化很多时候就是减少stop-the-world 的发生. JVM GC回收哪个区域内的垃圾? 需要注意的是,JV

Spark性能优化指南——高级篇

Spark性能优化指南--高级篇 [TOC] 前言 继基础篇讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化指南>的高级篇,将深入分析数据倾斜调优与shuffle调优,以解决更加棘手的性能问题. 数据倾斜调优 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题--数据倾斜,此时Spark作业的性能会比期望差很多.数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题,以保证Spark作业的性能. 数据倾斜发生时的现象 绝大多数tas

Mysql数据库性能优化(一)

参考 http://www.jb51.net/article/82254.htm 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据库时(尤其是查表时的SQL语句),我们都需要注意数据操作的性能.这里,我们不会讲过多的SQL语句的优化,而只是针对MySQL这一Web应用最多的数据库. mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面

Android应用程序性能优化Tips

主要介绍一些小细节的优化技巧,虽然这些小技巧不能较大幅度的提升应用性能,但是恰当的运用这些小技巧并发生累积效应的时候,对于整个App的性能提升还是有不小作用的.通常来说,选择合适的算法与数据结构会是你首要考虑的因素,在这篇文章中不会涉及这方面的知识点.你应该使用这篇文章中的小技巧作为平时写代码的习惯,这样能够提升代码的效率. 通常来说,高效的代码需要满足下面两个原则: 不要做冗余的工作 尽量避免执行过多的内存分配操作 To ensure your app performs well across

使用Html5+C#+微信 开发移动端游戏详细教程:(六)游戏界面布局与性能优化

本篇教程我们主要讲解在游戏界面上的布局一般遵循哪些原则和一些性能优化的通用方法. 接着教程(五),我们通过Loading类一次性加载了全部图像素材,现在要把我们所用到的素材变成图片对象显示在界面上,由上而下,首先是top层,top里面包涵了玩家(微信)头像,关卡信息,怪物血条信息,玩家金币,玩家宝石,玩家总攻击力. 定义函数 setTop 来初始化top层: function setTop() { TopDiv = new LSprite();//定义top层 var Topshape = ne