C # /. NET 프로그램 최적화를위한 팁 [닫힌]

요즘 최적화는 잃어버린 예술처럼 보입니다. 모든 프로그래머가 코드에서 최대한의 효율성을 뽑아 낸 적이 없었습니까? 눈 속에서 5 마일을 걷는 동안 자주 그렇게합니까?

잃어버린 예술을 되찾기 위해 C # /. NET 코드를 최적화하기 위해 간단하거나 복잡한 변경 사항에 대해 알고있는 몇 가지 팁은 무엇입니까? 수행하려는 작업에 따라 매우 광범위한 것이기 때문에 팁에 컨텍스트를 제공하는 데 도움이됩니다. 예를 들면 :

  • 많은 문자열을 함께 연결할 때 StringBuilder대신 사용하십시오. 이에 대한 경고는 하단의 링크를 참조하십시오.
  • string.Compare다음과 같이하는 대신 두 문자열을 비교하는 데 사용 합니다.string1.ToLower() == string2.ToLower()

지금까지의 일반적인 합의는 측정이 중요합니다. 이런 종류의 요점을 놓치게됩니다. 측정은 무엇이 잘못되었는지 또는 병목 현상이 발생한 경우 어떻게해야하는지 알려주지 않습니다. 한 번 문자열 연결 병목 현상에 부딪 쳤는데 어떻게해야할지 몰랐기 때문에이 팁이 유용합니다.

이 글을 게시하기위한 나의 요점은 일반적인 병목 현상에 대한 장소를 확보하고 문제가 발생하기 전에 피할 수있는 방법입니다. 누구나 맹목적으로 따라야하는 플러그 앤 플레이 코드에 관한 것이 아니라, 적어도 어느 정도는 성능을 고려해야하며,주의해야 할 몇 가지 일반적인 함정이 있다는 것을 이해하는 것이 더 중요합니다.

팁이 왜 유용하고 어디에 적용되어야하는지 아는 것도 유용 할 수 있습니다. 을 위해 StringBuilder팁 나는 오래전에했던 도움을 발견 존 소총의 사이트에 여기를 .



답변

요즘 최적화는 잃어버린 예술처럼 보입니다.

예를 들어 현미경의 제조가 예술로 실행되는 날이 하루에 한 번있었습니다. 광학 원리는 제대로 이해되지 않았습니다. 부품의 표준화가 없었습니다. 튜브와 기어, 렌즈는 고도로 숙련 된 작업자가 수작업으로 만들어야했습니다.

오늘날 현미경은 공학 분야로 생산됩니다. 물리학의 기본 원리는 매우 잘 이해되고 있으며, 기성 부품이 널리 사용 가능하며, 현미경 제작 엔지니어는 기기가 수행하도록 설계된 작업에 최적으로 최적화하는 방법에 대해 정보에 입각 한 선택을 할 수 있습니다.

성능 분석이 “잃어버린 예술”이라는 것은 아주 좋은 것입니다. 그 예술은 예술 로서 실행 되었습니다 . 최적화는 그것이 무엇인지에 대해 접근해야합니다 : 견고한 엔지니어링 원칙을주의 깊게 적용하여 해결할 수 있는 엔지니어링 문제 .

나는 사람들이 vbscript / jscript / 활성 서버 페이지 / VB / C # 코드를 최적화하는 데 사용할 수있는 “팁과 트릭”목록에 대해 수년에 걸쳐 수십 번 요청 받았습니다. 나는 항상 이것을 거부합니다. “팁과 트릭”을 강조하는 것은 성능에 접근하는 잘못된 방법입니다. 그런 식으로 이해하기 어렵고, 추론하기 어렵고, 유지하기 어려운 코드로 이어지며, 일반적으로 해당하는 간단한 코드보다 눈에 띄게 빠르지 않습니다.

성능에 접근하는 올바른 방법은 다른 문제와 마찬가지로 엔지니어링 문제로 접근하는 것입니다.

  • 의미 있고 측정 가능하며 고객 중심의 목표를 설정하십시오.
  • 현실적이지만 통제되고 반복 가능한 조건에서 이러한 목표에 대한 성능을 테스트하는 테스트 스위트를 빌드하십시오.
  • 이러한 제품군에서 목표를 달성하지 못하는 것으로 나타나면 프로파일 러와 같은 도구를 사용하여 이유를 파악하십시오.
  • 프로파일 러가 가장 성능이 떨어지는 하위 시스템으로 식별하는 것을 최적화하십시오. 각각의 성능 영향을 명확하게 이해할 수 있도록 모든 변경 사항에 대해 계속 프로파일 링하십시오.
  • (1) 목표를 달성하고 소프트웨어를 배송하거나, (2) 목표를 달성 할 수있는 수준으로 수정하거나, (3) 목표를 달성 할 수 없어 프로젝트가 취소 될 때까지 반복합니다.

이는 기능 추가와 같은 다른 엔지니어링 문제를 해결하는 것과 동일합니다. 기능에 대한 고객 중심 목표 설정, 견고한 구현에 대한 진행 상황 추적, 신중한 디버깅 분석을 통해 발견 된 문제 해결, 다음까지 반복 배송 또는 실패. 성능은 기능입니다.

복잡한 현대 시스템에 대한 성능 분석에는 사소하거나 비현실적인 상황에 좁게 적용 할 수있는 트릭으로 가득 찬 가방이 아닌 견고한 엔지니어링 원칙에 대한 규율과 초점이 ​​필요합니다. 팁과 트릭을 적용하여 실제 성능 문제를 한 번도 해결 한 적이 없습니다.


답변

좋은 프로파일 러를 얻으십시오.

좋은 프로파일 러없이 C # (실제로 모든 코드)을 최적화하려고 시도하지 마십시오. 실제로 샘플링 및 추적 프로파일 러를 모두 보유하면 크게 도움이됩니다.

좋은 프로파일 러가 없으면 잘못된 최적화를 만들 수 있으며 가장 중요한 것은 처음에 성능 문제가 아닌 루틴을 최적화하는 것입니다.

프로파일 링의 처음 세 단계는 항상 1) 측정, 2) 측정, 3) 측정 …입니다.


답변

최적화 지침 :

  1. 필요한 경우가 아니면하지 마십시오
  2. 개발자 대신 새로운 하드웨어를 문제에 던지는 것이 더 저렴하다면하지 마십시오.
  3. 생산과 동등한 환경에서 변화를 측정 할 수 없다면 그렇게하지 마십시오.
  4. CPU 메모리 프로파일 러 를 사용하는 방법을 모르면하지 마십시오.
  5. 코드를 읽을 수 없거나 유지 관리 할 수 ​​없게 만들 경우에는하지 마십시오.

프로세서가 계속 빨라짐에 따라 대부분의 애플리케이션에서 주요 병목 현상은 CPU가 아니라 대역폭입니다. 즉, 오프 칩 메모리 대역폭, 디스크 대역폭, 네트워크 대역폭입니다.

맨 끝에서 시작하십시오. YSlow를 사용하여 웹 사이트가 최종 사용자에게 느린 이유를 확인한 다음 뒤로 이동하여 데이터베이스 액세스가 너무 넓지 않고 (열) 너무 깊지 않도록 (행) 수정하십시오.

CPU 사용을 최적화하기 위해 무엇이든 할 가치가있는 매우 드문 경우에는 메모리 사용에 부정적인 영향을 미치지 않도록주의하십시오. 개발자가 CPU주기를 절약하기 위해 결과를 캐시하기 위해 메모리를 사용하려는 ‘최적화’를 보았습니다. 순 효과는 캐시 페이지 및 데이터베이스 결과에 사용 가능한 메모리를 줄이는 것이 었으며 이로 인해 응용 프로그램이 훨씬 느려졌습니다! (측정에 관한 규칙을 참조하십시오.)

또한 최적화되지 않은 ‘멍청한’알고리즘이 ‘영리한’최적화 알고리즘을 능가하는 경우도 보았습니다. 얼마나 훌륭한 컴파일러 작성자와 칩 설계자가 ‘비효율적 인’루핑 코드를 파이프 라이닝을 통해 온칩 메모리에서 완전히 실행할 수있는 매우 효율적인 코드로 바꾸 었는지 과소 평가하지 마십시오. ‘효율적’이라고 생각했던 언 래핑 된 내부 루프가있는 ‘영리한’트리 기반 알고리즘은 실행 중에 온칩 메모리에 머 무르지 못했기 때문에 단순히 이길 수 있습니다. (측정에 관한 규칙을 참조하십시오.)


답변

ORM으로 작업 할 때 N + 1 Selects를 알고 있어야합니다.

List<Order> _orders = _repository.GetOrders(DateTime.Now);
foreach(var order in _orders)
{
    Print(order.Customer.Name);
}

고객이 열심히로드하지 않으면 데이터베이스로 여러 번 왕복 할 수 있습니다.


답변

  • 매직 넘버를 사용하지 말고 열거를 사용하십시오.
  • 값을 하드 코딩하지 마십시오.
  • 형식이 안전하고 권투 및 개봉을 방지하므로 가능한 경우 제네릭을 사용하십시오.
  • 꼭 필요한 곳에 오류 처리기를 사용하십시오.
  • 폐기, 폐기, 폐기하십시오. CLR은 데이터베이스 연결을 닫는 방법을 알지 못하므로 사용 후 연결을 닫고 관리되지 않는 리소스를 폐기하십시오.
  • 상식을 사용하십시오!


답변

좋아, 나는 내가 가장 좋아하는 것을 던져야한다. 작업이 사람과의 상호 작용을 위해 충분히 길면 디버거에서 수동 중단을 사용하십시오.

Vs. 프로파일 러는 무슨 일이 일어나고 있는지 실제로 이해하는 데 사용할 수있는 호출 스택과 변수 값을 제공합니다.

이 작업을 10 ~ 20 회 수행하면 어떤 최적화가 실제로 효과를 가져올 수 있는지에 대한 좋은 아이디어를 얻을 수 있습니다.


답변

방법을 병목 현상으로 식별했지만 어떻게해야할지 모르겠다면 본질적으로 멈춘 것입니다.

그래서 몇 가지를 나열하겠습니다. 이 모든 일들은 실버 총알하지 당신은 아직 프로필을해야합니다 코드를. 저는 여러분 있는 일에 대한 제안을 하고 있으며 때로는 도움을 줄 수 있습니다. 특히 처음 세 개가 중요합니다.

  • 저수준 유형 또는 배열을 사용하여 문제를 해결해보십시오.
  • 문제는 종종 작습니다. 영리하지만 복잡한 알고리즘을 사용한다고해서 항상이기는 ​​것은 아닙니다. 특히 저수준 유형 (배열) 만 사용하는 코드로 덜 스마트 한 알고리즘을 표현할 수있는 경우에는 더욱 그렇습니다. 예를 들어 n <= 100에 대한 InsertionSort 대 MergeSort 또는 n <= 100에 대한 문제의 데이터 흐름 형식을 순진하게 해결하기 위해 비트 벡터를 사용하는 것과 비교하여 Tarjan의 Dominator 찾기 알고리즘을 사용합니다. (물론 100은 당신에게 몇 가지 아이디어를주기위한 것입니다- 프로필 !)
  • 더 큰 문제 인스턴스를 위해 다른 코드를 유지해야하는 경우에도 저수준 유형 (종종 크기가 64 미만인 문제 인스턴스)을 사용하여 해결할 수있는 특수 사례를 작성하는 것이 좋습니다.
  • 위의 두 가지 아이디어에 도움이되는 비트 연산을 배우십시오.
  • BitArray는 Dictionary 또는 List에 비해 친구가 될 수 있습니다. 그러나 구현이 최적이 아니라는 점에 유의하십시오. 더 빠른 버전을 직접 작성할 수 있습니다. 인수가 범위를 벗어 났는지 등을 테스트하는 대신 인덱스가 범위를 벗어날 수 없도록 알고리즘을 구조화 할 수 있지만 표준 BitArray에서 검사를 제거 할 수 없으며 자유롭지 않습니다 .
  • 저수준 유형의 배열만으로 수행 할 수있는 작업의 예로 BitMatrix는 ulong 의 배열 로 구현할 수있는 다소 강력한 구조 이며 ulong을 “front”로 사용하여 탐색 할 수도 있습니다. 일정한 시간의 최하위 비트 (Breadth First Search의 큐와 비교-하지만 분명히 순서는 다르며 순전히 항목을 찾는 순서가 아니라 항목 의 인덱스 에 따라 다릅니다 ).
  • 나눗셈과 모듈로는 오른쪽이 상수가 아니면 정말 느립니다.
  • 부동 소수점 연산은 하지 더 이상 느린 정수 수학에 비해 일반적으로 (하지 “당신이 할 수있는 일”, 그러나 “당신이하고 건너 뛸 수 있습니다 뭔가”)
  • 분기는 무료아닙니다 . 간단한 산술 (나눗셈 또는 모듈로 제외)을 사용하여 피할 수 있다면 때때로 성능을 얻을 수 있습니다. 분기를 루프 외부로 이동하는 것은 거의 항상 좋은 생각입니다.