◆ Performance Tips for All Applications

1. Exception 처리를 가급적 줄여라 : 매 Exception 처리마다 성능이 엄청나게 떨어진다.

  예) 예제에서 throw Exception을 주석처리하고 실행속도를 비교해보라!
public static void Main(string[] args){
int j = 0;
for(int i = 0; i < 10000; i++){
try{   
j = i;
throw new System.Exception();
} catch {}
}
System.Console.Write(j);
return;   
}

 ☞ 런타임이 발생시키는 Exception도 있으므로 주의할 것.
    예) Response.Redirect()는 ThreadAbort exception을 발생시킨다.
 ☞ VB에서는 overflow나 divide-by-zero 처리를 위한 int값 검사를 기본적으로 하도록 되어 있음.
 ☞ COM을 사용한다면 HRESULTS가 exception을 리턴할 수도 있음을 명심할 것.

2. 한번의 호출로 가급적 많은 일을 하게 하라. 호출이 많을수록 부하가 커진다.

3. boxing-unboxing 작업이 별로 없는 환경에서는 가급적 값형식(ValueTypes)으로 설계하라.

  예) struct형식이 훨씬 빠르다!
using System;

namespace ConsoleApplication{ 

public struct foo{
public foo(double arg){ this.y = arg; }
public double y;
}
public class bar{
public bar(double arg){ this.y = arg; }
public double y;
}
class Class1{
static void Main(string[] args){
System.Console.WriteLine("starting struct loop...");
for(int i = 0; i < 50000000; i++)
{foo test = new foo(3.14);}
System.Console.WriteLine("struct loop complete. 
                       starting object loop...");
for(int i = 0; i < 50000000; i++)
{bar test2 = new bar(3.14); }
System.Console.WriteLine("All done");
}
}
}

 ☞ 그러나, 이러한 값형식(ValueTypes)은 개체형식(Objects)보다 유연성이 훨씬 없으므로 적절히
    사용하지 않으면 성능악화를 초래할 수 있다.
 ☞ 위 예제에서 foo와 bar를 배열이나 hashtable로 저장하는 단순한 boxing-unboxing작업으로만
    수정해도 값형식의 성능이 상당히 떨어지게 됨을 볼 수 있을 것이다.

4. 그룹(여러개의 아이템)을 추가할 때는 Add() 함수 대신 AddRange() 함수를 사용하라.

5. 작업환경 관리를 위해 어셈블리 갯수를 최소한으로 줄여라.

6. String 반복작업에는 foreach 대신 for 루프문을 사용하는 것이 성능향상에 좋다.

  예) 예제에서 마지막 for문 대신 foreach문의 주석을 풀고 실행해보라!
public static void Main(string[] args) {
string s = "monkeys!";
int dummy = 0;

System.Text.StringBuilder sb = new System.Text.StringBuilder(s);
for(int i = 0; i < 1000000; i++)
sb.Append(s);
s = sb.ToString();
//foreach (char c in s) dummy++;
for (int i = 0; i < 1000000; i++)
dummy++;
return;   
}

7. 복잡한 문자열 처리는 단순 문자열 연결보다 StringBuilder를 사용하는 것이 훨씬 좋다.

  예1) 단순 문자열 처리의 경우 : 느리다.
namespace ConsoleApplication1.Feedback{
using System;

public class Feedback{
public Feedback(){
text = "You have ordered: \n";
}

public string text;

public static int Main(string[] args) {
Feedback test = new Feedback();
String str = test.text;
for(int i=0;i<50000;i++){
str = str + "blue_toothbrush";
}
System.Console.Out.WriteLine("done");
return 0;
}
}
}

  예2) StringBuilder를 사용한 경우 : 훨씬 빠르다.
namespace ConsoleApplication1.Feedback{
using System;

public class Feedback{
public Feedback(){
text = "You have ordered: \n";
}

public string text;

public static int Main(string[] args) {
Feedback test = new Feedback();
System.Text.StringBuilder SB = new System.Text.StringBuilder(test.text);
for(int i=0;i<50000;i++){
SB.Append("blue_toothbrush");
}
System.Console.Out.WriteLine("done");
return 0;
}
}
}

 ☞ 성능이 좋은 서버에서는 쉽게 차이를 느낄 수 없으나, 10개 이상의 문자열 조작이 동시에
    발생하면 차이를 쉽게 느낄 수 있다.

8. Windows Forms 응용프로그램은 배포전에 Precompile하라. ngen.exe라는 툴로 인스톨할 때, 혹은
  배포전에 Precompile할 것인지 선택할 수 있다.

9. 다차원 배열(rectangular arrays)보다 중첩배열(jagged arrays)이 성능이 더 좋다.

------------------------------------------------------
C# Visual Basic 7 
------------------------------------------------------
Assignment (jagged)   14.16 12.24 
Assignment (rectangular) 8.37 8.62
Neural Net (jagged) 4.48 4.58
Neural net (rectangular) 3.00 3.13
Numeric Sort (jagged) 4.88 5.07
Numeric Sort (rectangular) 2.05 2.06
------------------------------------------------------
(* 숫자가 높을수록 성능이 좋다)

10. IO 버퍼 크기를 4KB ~ 8KB로 유지하는 것이 성능이 가장 좋다.

11. 비동기 IO를 주의깊게 사용하라. 적절히만 사용하면 10배가량 성능 개선 효과가 있다.


◆ Tips for Database Access

1. 최적화된 공급자(Provider)를 사용하라. SQL Server에는 System.Data.SqlClient가 최적이다.

2. 가능한한 DataSet 대신 SqlDataReader를 사용하라.

------------------------
ADO SQL 
------------------------
DataSet 801 2507 
DataReader 1083 4585 
------------------------
(* 숫자가 높을수록 성능이 좋다)

3. 멀티프로세서 서버에서는 Mscorwks.dll 대신 Mscorsvr.dll를 사용하라.

4. 가능한한 모든 쿼리문을 저장 프로시저로 대치하라.

5. 동적 연결 문자열을 사용할 때는 풀링을 고려하여 항상 동일하게 적용되도록 주의하라.

6. 사용하지 않는 기능은 꺼라(Turn off).

  예) 자동 트랜잭션 참가기능은, 사용하지 않으면 꺼라.
SqlConnection conn = new SqlConnection(
"Server=mysrv01;
Integrated Security=true;
Enlist=false");

  예) 기본키 정보가 필요하지 않으면 사용하지 말라. (MissingSchemaAction.AddWithKey를 사용하지 말라.)
public DataSet SelectSqlSrvRows(DataSet dataset,string connection,string query){
   SqlConnection conn = new SqlConnection(connection);
   SqlDataAdapter adapter = new SqlDataAdapter();
   adapter.SelectCommand = new SqlCommand(query, conn);
   adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
   adapter.Fill(dataset);
   return dataset;
}

7. SqlDataAdapter 사용시, 비록 편리하더라도, 자동 생성되는 Command 개체를 사용하지 말라.

8. ADO 설계시 다음 사항을 주의하라.

 ☞ 쿼리문에 있는 모든 항목이 리턴된다.
 ☞ 서버측 커서가 필요하다면 저장 프로시저를 사용하고, 가급적 서버측 커서 사용을 피하라.
 ☞ 비상태(stateless), 비연결(connectionless) 페이징 기법을 활용하라.
 
9. 꼭 필요한 데이터만 DataSet에 저장하라.

10. SqlDataReader 사용시, 가능한 한 자주 순차적 접근(CommandBehavior.SequentialAccess)을 사용하라.


◆ Performance Tips for ASP.NET Applications

1. 캐시를 적극적으로 사용하라.

  예)
Output Caching - Stores the static result of an ASP request. 
Specified using the <@% OutputCache %> directive: 

* Duration - Time item exists in the cache 
* VaryByParam - Varies cache entries by Get/Post params 
* VaryByHeader - Varies cache entries by Http header 
* VaryByCustom - Varies cache entries by browser 
* Override to vary by whatever you want: 
- Fragment Caching - When it is not possible to store an entire page
 (privacy, personalization, dynamic content), you can use fragment caching to store 
 parts of it for quicker retrieval later. 
a) VaryByControl - Varies the cached items by values of a control 

- Cache API - Provides extremely fine granularity for caching by keeping a hashtable 
 of cached objects in memory (System.web.UI.caching). It also: 
a) Includes Dependencies (key, file, time) 
b) Automatically expires unused items 
c) Supports Callbacks 

2. Session State는 필요할 때만 사용하라.

<%@ EnabledSessionState = false %>
<%@ EnabledSessionState = readonly %>

3. View State는 필요할 때만 사용하라.

<%@ EnabledViewState = false %>

4. STA COM 사용을 피하라. MTA COM을 사용하라.

 ☞ 어쩔 수 없이 사용하게 될 경우에는 <%@ Page AspCompat = "true"%>를 사용하라.

5. 웹에 배포하기 전에 일괄 컴파일(Batch Compile)하라.

6. 불필요하거나 사용되지 않는 Http 모듈을 제거하라.

7. Autoeventwireup 특성을 사용하지 말 것.

<%@ Page AutoEventWireup="false" %>

8. UTF 인코딩이 필요하지 않은 경우에는 항상 ASCII 인코딩을 사용하라.

9. 최적화된 인증 프로시저를 사용하라.

 ☞ None, Windows, Forms, Passport 순으로 성능이 저하된다.


◆ Tips for Porting and Developing in Visual Basic

1. 에러 처리는 on Error Goto문 대신 Try/Catch 블록을 사용하는 것이 훨씬 낫다.

  예1) 두 함수 처리에 각각 244 ms, 179 ms 소요됨
Sub SubWithError()
On Error Goto SWETrap
Dim x As Integer
Dim y As Integer
x = x / y
SWETrap:
Exit Sub
End Sub

Sub SubWithErrorResumeLabel()
On Error Goto SWERLTrap
Dim x As Integer
Dim y As Integer
x = x / y 
SWERLTrap:
Resume SWERLExit
Exit Sub

SWERLExit:
Exit Sub
End Sub

  예2) 두 함수 처리에 각각 169 ms, 164 ms 소요됨
Sub SubWithError()
Dim x As Integer
Dim y As Integer
Try
x = x / y
Catch
Return
End Try
End Sub

Sub SubWithErrorResumeLabel()
Dim x As Integer
Dim y As Integer
Try
x = x / y
Catch
Goto SWERLExit
End Try

SWERLExit:
Return
End Sub

2. 전기(초기) 바인딩(Early Binding)을 사용하라.

3. Option Strict와 Option Explicit를 사용하라.

4. 텍스트 비교에 Binary Compare를 사용하라.

5. Format() 함수의 사용을 최소화하라. 대신 ToString()함수를 권장한다.

6. Char() 대신 CharW()를 사용하라. CLR은 내부적으로 Unicode를 사용한다.

7. 변수 할당시 변수 이름을 두번 쓰는 것을 피하라.

  예) exp = exp + val 대신 exp += val 로 쓰라.

8. 불필요한 참조(byRef)를 피하라. heap을 사용하는 것이 stack을 사용하는 것보다 느리다.

9. 문자열 연결은 여러 라인에 걸쳐 하지 말고 하나의 표현식으로 표현하라.

 ☞ 문자열은 수정될 때마다 새로 String 개체를 생성하게 된다.

10. 함수 끝에 항상 Return문을 써주는 것이 성능향상에 도움이 된다.


◆ Tips for Porting and Developing in Managed C++

1. 관리되는 코드와 관리되지 않는 코드를 동시에 사용할 수 있다.

 ☞ 성능 향상에 필요한 내용을 선택할 수 있다.
 
2. 모든 C++ 코드는 MSIL(중간언어)로 컴파일될 수 있다.

3. C#이나 VB에 비해 여러가지 장점이 있다.

4. 일반화된 byref 포인터

 ☞ 배열의 중간을 가로채어 값을 리턴할 수도 있다.
  예)
Byte* AddrInArray( Byte b[] ) {
return &b[5];
}
  
 ☞ 포인터를 사용하여 배열에서 루프를 돌 수도 있다.
  예)
System::Char* PtrToStringChars(System::String*);   
for( Char*pC = PtrToStringChars(S"boo");
pC != NULL;
pC++ )
{
     ... *pC ...
}

 ☞ linked-list를 쉽게 구현할 수 있다.
  예)
Node **w = &Head;
while(true) {
if( *w == 0 || val < (*w)->val ) {
Node *t = new Node(val,*w);
*w = t;
break;
}
w = &(*w)->next;
}

 ☞ 포인터의 위치를 자유롭게 이동시킬 수 있다.
  예)
if( Head==null || val < Head.val ) {
Node t = new Node(val,Head);
Head = t;
}
else {
// we know at least one node exists,
// so we can look 1 node ahead
Node w=Head;
while(true) {
if( w.next == null || val < w.next.val ){
Node t = new Node(val,w.next.next);
w.next = t;
break;
}
w = w.next;
}
}

5. Boxed Type으로의 접근이 가능하다.

 예1) C++에서는 Boxed type을 이용하여 직접 형식전환이 가능하다.
__value struct V {
int i;
};
int main() {
V v = {10};
__box V *pbV = __box(v);
pbV->i += 10;           // update without casting
}  
 
 예2) C#에서는 한단계 더 거쳐야 한다.
struct B { public int i; }
static void Main() {
B b = new B();
b.i = 5;
object o = b;         // implicit box
B b2 = (B)o;            // explicit unbox
b2.i++;               // update
o = b2;               // implicit re-box
}

6. STL Collections vs. Managed Collections의 장단점

 ☞ STL Collection은 빠르지만, CLR framework는 boxing-unboxing에 의해 영향을 많이 받는다.
 ☞ 이러한 boxing-unboxing 문제점은 금방 해결될 것이다.

7. 가급적 Stack관리 개체(stack-managed objects : ValueTypes)를 사용하라. 

 ☞ Stack이나 Heap에 의해 관리되는 개체를 사용할 수도 있으나 주의해야 한다.
...




Posted by 떼르미
,


자바스크립트를 허용해주세요!
Please Enable JavaScript![ Enable JavaScript ]