대기 시간이 짧은 코드가 때때로 "못생긴"상태 여야합니까?


21

(이것은 주로 근거없는 의견으로 응답하는 사람들을 피하기 위해 대기 시간이 짧은 시스템에 대한 특정 지식을 가진 사람들을 대상으로합니다).

"좋은"객체 지향 코드를 작성하는 것과 매우 빠른 저 지연 코드를 작성하는 것 사이에 상충 관계가 있다고 생각하십니까? 예를 들어, C ++에서 가상 함수를 피하거나 다형성의 오버 헤드를 피하는 등 불쾌한 것처럼 보이지만 매우 빠른 코드를 다시 작성 하는가?

그것은 추악한 것처럼 보이는지 (보관 가능한 한) 누가 걱정하는지-속도가 필요하다면 속도가 필요합니까?

그런 분야에서 일한 사람들의 의견을 듣고 싶습니다.


1
@ user997112 : 가까운 이유는 자명하다. : 그것은 말한다 . 우리는 대답은 사실, 참조, 또는 특정 전문 지식에 의해 지원 될 수 있지만,이 질문은 가능성이 SOLICIT 논쟁, 인수, 폴링, 또는 확장 된 논의를 할 것으로 예상 " 합니까이 반드시 그들에게있는 거 정확한 의미하지만, 가까이이었다 세 명의 가까운 유권자가 선택한 이유
Robert Harvey

일화 적으로, 나는이 질문이 많은 표를 얻는 이유는 그것이 얇게 드러난 폭군으로 인식 될 수 있기 때문이라고 말하고있다.
Robert Harvey

8
나는 내 목을 찌를 것이다. 나는 질문자가 자신의 질문에 거의 답을한다고 생각하기 때문에 세 번째 투표를 "비 건설적이지 않은"것으로 마감했다. 작업을 수행하기에 충분히 빨리 실행되지 않는 "아름다운"코드는 대기 시간 요구 사항을 충족하지 못했습니다. 충분히 빠르게 실행되는 "못생긴"코드는 좋은 문서를 통해 유지 관리가 더 쉬워 질 수 있습니다. 아름다움이나 추악함을 측정하는 방법은 또 다른 질문의 주제입니다.
Blrfl

1
LMAX Disruptor의 소스 코드가 너무 추악하지 않습니다. '안전하지 않은 클래스 (Java의 보안 모델)'에 대한 부분과 일부 하드웨어 수정 (캐시 라인 패딩 변수)이 있지만 읽기 쉬운 IMO입니다.
James

5
@ Carson63000, user1598390 및 기타 관심있는 사람 : 질문이 종료 된 경우 메타 사이트 의 폐쇄에 대해 언제든지 문의하십시오 . 의견에 대한 폐쇄, 특히 발생하지 않은 폐쇄에 대해서는 논의 할 필요 가 없습니다 . 또한 모든 비공개 질문을 다시 열 수 있습니다. 세상 끝이 아닙니다. 물론 마야인이 옳다면, 당신을 모두 아는 것이 좋았습니다!
yannis

답변:


31

"좋은"객체 지향 코드를 작성하는 것과 매우 짧은 대기 시간 코드를 작성하는 것 사이에 절충이 있다고 생각하십니까?

예.

이것이 바로 "조기 최적화"라는 문구가 존재하는 이유입니다. 개발자가 성능 을 측정 하고 성능 에 차이를 줄 수있는 코드 만 최적화하는 동시에 애플리케이션 아키텍처를 처음부터 현명하게 설계하여로드가 많이 걸리지 않도록해야합니다.

그렇게하면 가능한 한 최대한 잘 설계되고 객체 지향적 인 코드를 유지하고 중요한 부분 만 못 생겨서 최적화 할 수 있습니다.


15
"작동하고 빨리 만들어라" 이 답변은 질문을 읽을 때 생각했던 모든 것을 거의 다룹니다.
Carson63000

13
나는 "생각하지 않는다, 측정"추가 할 것입니다
마티 Verburg

1
가독성을 희생하지 않는 한 기본 작업 회피에 일부를 넣는 것이 가치 있다고 생각합니다. 간결하고 읽기 쉬우 며 필요한 작업 만 수행하면 다른 개발자와 마찬가지로 간접적 인 장기 성과가 발생하여 코드를 작성하는 데 도움이되므로 노력이 중복되거나 잘못된 가정이되지 않습니다. 작동 방식에 대해
Erik Reppen

1
"조기 최적화"-최적화 된 코드가 최적화되지 않은 코드처럼 "좋은"경우에도 여전히 적용됩니다. 요점은 속도 / 달성 할 필요가없는 것을 목표로 시간을 낭비하지 않는 것입니다. 실제로 최적화가 항상 속도에 관한 것은 아니며 "아름다움"에 대한 불필요한 최적화와 같은 것이있을 것입니다. 코드를 읽고 유지 관리하기 위해 훌륭한 예술 작품 일 필요는 없습니다.
Steve314

나는 두 번째 @ Steve314. 나는 제품의 성능을 주도하며 종종 일종의 성능 최적화로 거슬러 올라갈 수있는 지나치게 복잡한 코드를 찾습니다. 코드를 단순화하면 성능이 크게 향상되는 경우가 많습니다. 그러한 예 중 하나를 단순화하면 성능이 5 배 향상되었습니다 (수천 줄의 코드 감소). 분명히 아무도 실제로 측정하는 데 시간이 걸리지 않았으며 아마도 느린 코드 라고 생각한 것을 조기에 최적화하지 않았습니다 .
Brandon

5

예, 내가 제공하는 예는 C ++ 대 Java가 아니라 Assembly vs. COBOL입니다.

두 언어 모두 매우 빠르지 만 컴파일 할 때 COBOL조차도 명령어 세트에 배치되는 명령어가 어셈블리에 직접 작성하는 것보다 반드시 필요한 것은 아닙니다.

C ++에서 상속 / 다형성을 사용하는 것과 "추악한 코드를 작성하는"질문에 동일한 아이디어를 직접 적용 할 수 있습니다. 최종 사용자가 1 초 미만의 트랜잭션 타임 프레임을 필요로한다면 추악한 코드를 작성해야한다고 생각합니다. 어떻게되는지에 상관없이 프로그래머에게 맡겨야합니다.

즉, 주석을 자유롭게 사용하면 코드가 아무리 추악하더라도 프로그래머 기능과 유지 관리 성이 크게 향상됩니다.


3

그렇습니다. 따라서, 더 빠르고 더 못생긴 코드는 더 이상 필요하지 않습니다. "빠른 코드"의 양적 이점은 해당 속도를 달성하는 데 필요한 코드 변경의 유지 관리 복잡성에 가중되어야합니다.

트레이드 오프는 비즈니스 비용에서 비롯됩니다. 더 복잡한 코드는보다 숙련 된 프로그래머 (및 CPU 아키텍처 및 설계 지식이있는 기술과 같이보다 집중된 기술 세트를 가진 프로그래머)를 필요로하며 코드를 읽고 이해하고 버그를 수정하는 데 더 많은 시간이 걸립니다. 이러한 코드를 개발 및 유지 관리하는 데 드는 비즈니스 비용은 일반적으로 작성된 코드보다 10x-100x입니다.

이 유지 관리 비용은 고객이 매우 빠른 소프트웨어에 대해 매우 높은 보험료를 기꺼이 지불하는 일부 산업에서 정당화 될 수 있습니다.

일부 속도 최적화는 다른 것보다 ROI (Return-On-Investment)를 향상시킵니다. 즉, 일부 최적화 기술은 일반적으로 작성된 코드와 비교하여 코드 유지 관리 성 (높은 수준의 구조 및 낮은 수준의 가독성 유지)에 미치는 영향을 줄이면서 적용될 수 있습니다.

따라서 사업주는 다음을 수행해야합니다.

  • 비용과 혜택을보고
  • 측정 및 계산
    • 프로그래머가 프로그램 속도를 측정하도록하십시오
    • 프로그래머에게 최적화에 필요한 개발 시간을 추정하게하십시오
    • 빠른 소프트웨어로 인한 수입 증가에 대한 자체 추정
    • 소프트웨어 설계자 또는 QA 관리자가 소스 코드의 직관적 성과 가독성 감소로 인한 단점을 질적으로 측정하도록합니다.
  • 또한 소프트웨어 최적화의 낮은 성과를 우선시하십시오.

이러한 장단점은 상황에 따라 매우 다릅니다.

관리자 및 제품 소유자의 참여 없이는이를 최적으로 결정할 수 없습니다.

이들은 플랫폼에 따라 매우 다릅니다. 예를 들어, 데스크탑과 모바일 CPU는 다른 고려 사항이 있습니다. 서버 및 클라이언트 응용 프로그램도 다른 고려 사항이 있습니다.


일반적으로 빠른 코드는 일반적으로 작성된 코드와 다르게 보입니다. 다른 코드는 읽는 데 시간이 더 걸립니다. 그것이 추함을 의미하는지 여부는 보는 사람의 눈에 있습니다.

내가 어떤 노출을 가지고있는 기술은 다음과 같습니다 : (모든 수준의 전문 지식을 요구하지 않고) 짧은 벡터 최적화 (SIMD), 세분화 된 작업 병렬 처리, 메모리 사전 할당 및 객체 재사용.

SIMD는 일반적으로 높은 수준의 구조적 변경이 필요하지 않지만 (API가 병목 현상 방지를 염두에두고 설계된 경우에도) 낮은 수준의 가독성에 심각한 영향을 미칩니다.

일부 알고리즘은 쉽게 SIMD로 변환 할 수 있습니다 (당황스럽게 벡터화 가능). 일부 알고리즘은 SIMD를 사용하기 위해 더 많은 계산 재 배열이 필요합니다. 웨이브 프론트 SIMD 병렬 처리와 같은 극단적 인 경우에는 완전히 새로운 알고리즘 (및 특허 가능한 구현)을 작성하여 활용해야합니다.

세분화 된 작업 병렬화를 위해서는 알고리즘을 데이터 흐름 그래프로 재 배열해야하며 추가 마진 이익을 얻을 수 없을 때까지 알고리즘에 기능적 (계산) 분해를 반복적으로 적용해야합니다. 분해 단계는 일반적으로 기능적 프로그래밍에서 빌린 개념 인 연속 스타일과 연결됩니다.

기능적 (계산적) 분해에 의해, 일반적으로 선형적이고 개념적으로 명확한 순서로 작성 될 수있는 알고리즘 (작성된 순서와 동일하게 실행 가능한 코드 라인)은 조각으로 나누어 여러 함수로 분산되어야합니다. 또는 수업. (아래의 알고리즘 객관화 참조) 이 변경으로 인해 분해 설계 프로세스에 익숙하지 않은 동료 프로그래머는 이러한 코드를 발생시킬 수 있습니다.

이러한 코드를 유지 관리하기 위해서는 해당 코드 작성자가 코드 작성 또는 정상적으로 작성된 코드에 대해 수행 된 UML 다이어그램을 훨씬 능가하는 정교한 알고리즘 문서를 작성해야합니다. 이것은 연구원들이 학술 논문을 작성하는 방식과 유사합니다.


아니요, 빠른 코드는 객체 지향과 모순 될 필요가 없습니다.

다시 말해서, 여전히 객체 지향적 인 매우 빠른 소프트웨어를 구현할 수 있습니다. 그러나 (대부분의 계산이 발생하는 너트 앤 볼트 레벨에서) 해당 구현의 최하위를 향하여 객체 설계는 객체 지향 설계 (OOD)에서 얻은 설계와 크게 다를 수 있습니다. 하위 레벨 디자인은 알고리즘-개념화에 맞춰져 있습니다.

캡슐화, 다형성 및 구성과 같은 객체 지향 프로그래밍 (OOP) 의 몇 가지 이점은 여전히 낮은 수준의 알고리즘 객체화에서 얻을 수 있습니다. 이것이이 수준에서 OOP를 사용하기위한 주된 이유입니다.

객체 지향 설계 (OOD) 의 대부분의 이점 이 손실됩니다. 가장 중요한 것은 저수준 디자인에는 직관적이지 않다는 것입니다. 동료 프로그래머는 알고리즘이 처음에 어떻게 변환되고 분해되었는지를 완전히 이해하지 않으면 하위 수준 코드로 작업하는 방법을 배울 수 없으며 결과 코드에서는 이러한 이해를 얻을 수 없습니다.


2

예, 때로는 필요한 시간에 작동하기 위해 코드가 "추악한"상태 여야하지만 모든 코드가 추한 것은 아닙니다. "추악한"코드를 찾기 위해서는 성능을 테스트하고 프로파일 링해야하며, 해당 섹션에는 주석이 표시되어야합니다. 누군가 성능상의 이유로 주장하는 잘못 설계된 코드를 많이 작성하고 있다면 그것을 증명하도록하십시오.

속도는 프로그램의 다른 요구 사항과 마찬가지로 중요합니다. 유도 미사일에 잘못된 수정을하는 것은 충돌 후 올바른 수정을 제공하는 것과 같습니다. 유지 관리 성은 항상 작업 코드의 두 번째 관심사입니다.


2

필자가 추출한 일부 연구 결과는 코드를 읽기 어려운 코드가 읽기 어려운 코드보다 더 빠르다는 것을 나타냅니다. 부분적으로 이것은 최적화 프로그램이 설계된 방식 때문입니다. 중간 계산 결과로 변수를 수행하는 것보다 변수를 레지스터로 최적화하는 것이 훨씬 더 좋습니다. 최종 결과로 이어지는 단일 연산자를 사용하는 긴 할당 시퀀스는 긴 복잡한 방정식보다 더 잘 최적화 될 수 있습니다. 최신 옵티마이 저는 깨끗하고 복잡한 코드의 차이를 줄 였지만 코드를 제거하지는 않았을 것입니다.

루프 언 롤링과 같은 다른 최적화는 필요할 때 깔끔하게 추가 할 수 있습니다.

성능 향상을 위해 추가 된 최적화에는 적절한 설명이 수반되어야합니다. 여기에는 최적화로 추가되었다는 진술이 포함되어야하며, 가급적 전후의 성능 측정 값이 있어야합니다.

80/20 규칙이 내가 최적화 한 코드에 적용된다는 것을 알았습니다. 경험상 적어도 80 % 이상 걸리지 않는 것은 최적화하지 않습니다. 그런 다음 10 배의 성능 향상을 목표로합니다. 이것은 약 4 배의 성능을 향상시킵니다. 내가 구현 한 대부분의 최적화는 코드를 "아름답게"크게 줄이지 않았습니다. 귀하의 마일리지가 다를 수 있습니다.


2

추악한 경우, 다른 개발자가 재사용하거나 이해해야하는 수준에서 읽기 / 이해하기 어려운 경우 우아하고 읽기 쉬운 코드는 거의 언제나 유지해야하는 앱에서 장기적으로 성능을 향상시킵니다.

그렇지 않으면 때로는 킬러 인터페이스가있는 아름다운 상자에 못생긴 상자를 만들기에 충분한 성능상의 승리가 있지만 내 경험상 이것은 매우 드문 딜레마입니다.

갈 때 기본적인 작업 회피에 대해 생각하십시오. 성능 문제가 실제로 발생할 때의 비법을 저장하십시오. 그리고 특정 최적화에 익숙해 져서 만 누군가가 이해할 수있는 내용을 작성해야하는 경우 코드 관점의 재사용을 통해 추악한 부분을 이해하기 쉽게 만들 수 있습니다. 개발자가 다음 사람이 상속 할 대상에 대해 지나치게 열심히 생각했기 때문에 비참하게 수행되는 코드는 그렇지 않지만 자주 변경하는 것이 앱 (내 경험상 대부분의 웹 앱)의 유일한 상수 인 경우 수정하기 어려운 것은 당황한 혼란이 코드베이스 전체에서 팝업되기 시작하도록 실제로 구걸하는 것입니다. 깨끗하고 마른 것이 장기적으로 성능에 더 좋습니다.


나는 두 가지 변화를 제안하고 싶습니다 : (1) 속도가 필요한 곳이 있습니다. 그러한 곳에서는 구현 을 이해하기 쉽게 만드는 것보다 인터페이스 를 이해하기 쉽게 만드는 것이 가치가 있다고 생각합니다 . 후자는 훨씬 더 어려울 수 있기 때문입니다. (2) "비참하게 거의 수행하지 않는 코드는 그렇게하지 않는다 ...", "코드의 우아함과 단순성에 중점을 두는 것은 비참한 성능의 원인은 거의 없다. 빈번한 변경은 전자가 더 중요하다. ... "
rwong 님이

OOPish 대화에서 구현은 단어를 잘못 선택했습니다. 나는 재사용과 편집의 용이성 측면에서 의미했다. # 2, 나는 2가 본질적으로 내가하고있는 포인트라는 것을 입증하기 위해 문장을 추가했습니다.
Erik Reppen

1

복잡 하고 못생긴 것은 같은 것이 아닙니다. 많은 특수한 경우가 있으며 마지막 성능 저하를 없애도록 최적화되어 있으며 처음 에는 복잡한 연결 및 종속성 처럼 보이는 코드 는 실제로 이해하면 매우 신중하게 설계되고 매우 아름답습니다. 실제로 성능 (지연 시간 등으로 측정 되든)이 매우 복잡한 코드를 정당화하기에 충분히 중요한 경우 코드 잘 설계 해야합니다 . 그렇지 않다면 복잡한 모든 것이 단순한 솔루션보다 실제로 더 낫다는 것을 확신 할 수 없습니다.

추악한 코드는 나쁘고 부적절하게 고려되거나 불필요하게 복잡한 코드입니다. 코드에서 수행해야 할 기능을 원치 않는다고 생각합니다.


1

"좋은"객체 지향 코드를 작성하는 것과 매우 빠른 저 지연 코드를 작성하는 것 사이에 상충 관계가 있다고 생각하십니까? 예를 들어, C ++에서 가상 함수를 피하거나 다형성의 오버 헤드를 피하는 등 불쾌한 것처럼 보이지만 매우 빠른 코드를 다시 작성 하는가?

지연 시간보다 처리량에 조금 더 초점을 맞춘 분야에서 일하지만 성능이 매우 중요하며 "sorta" 라고 말합니다 .

그러나 문제는 너무 많은 사람들이 성능에 대한 개념이 완전히 잘못되었다는 것입니다. 초보자는 종종 모든 것을 잘못 이해하고 있으며 "계산 비용"이라는 전체 개념 모델을 다시 작업해야합니다. 알고리즘 복잡성 만 있으면 얻을 수있는 유일한 것이됩니다. 중간체는 많은 일을 잘못합니다. 전문가들은 문제가 있습니다.

캐시 미스 및 분기 오판과 같은 메트릭을 제공 할 수있는 정확한 도구를 사용하여 측정하면 해당 분야의 모든 수준의 전문 지식을 유지할 수 있습니다.

측정은 또한 최적화하지 않아야 할 사항을 지적합니다 . 전문가들은 종종 측정 된 핫스팟을 최적화하고 느려질 수있는 것에 대한 직감을 기반으로 어둠 속에서 야생 찌르기를 최적화하지 않기 때문에 초보자보다 최적화에 더 적은 시간을 소비 합니다. 코드베이스의 다른 모든 줄에 대해).

성능을위한 설계

이를 제외하고, 인터페이스 디자인 에서처럼 성능을위한 디자인의 핵심은 디자인 부분 에서 나옵니다 . 경험이 부족한 문제 중 하나는 일반화 된 컨텍스트에서 간접 함수 호출 비용과 같은 절대 구현 메트릭이 조기에 전환되는 경향이 있다는 것입니다. 분기 관점이 아니라 관점)은 전체 코드베이스에서이를 피해야하는 이유입니다.

비용은 상대적 입니다. 간접 함수 호출에는 비용이 있지만 모든 비용은 상대적입니다. 수백만 개의 요소를 반복하는 함수를 호출하기 위해 한 번 비용을 지불하는 경우이 비용에 대해 걱정하는 것은 10 억 달러짜리 제품을 구매하기 위해 돈을 낭비하는 데 시간이 걸리는 것입니다. 1 페니가 너무 비쌌습니다.

거친 인터페이스 디자인

성능 의 인터페이스 디자인 측면은 종종 이러한 비용을보다 거친 수준으로 밀어 넣기 위해 종종 추구합니다. 예를 들어, 단일 입자에 대한 런타임 추상화 비용을 지불하는 대신, 그 비용을 입자 시스템 / 이미 터 레벨로 밀어 넣어 효과적으로 입자를 구현 세부 사항 및 / 또는 단순히이 입자 수집의 원시 데이터로 렌더링 할 수 있습니다.

따라서 객체 지향 디자인은 성능 설계 (지연 시간 또는 처리량 등)와 호환되지 않아도되지만 점점 더 세분화 된 객체를 모델링하는 데 중점을 둔 언어로 된 유혹이있을 수 있으며 최신 옵티마이 저는 도움. 소프트웨어의 메모리 액세스 패턴에 대해 효율적인 SoA 표현을 생성하는 방식으로 단일 지점을 나타내는 클래스를 통합하는 등의 작업을 수행 할 수 없습니다. 조잡한 수준으로 모델링 된 인터페이스 디자인을 가진 포인트 모음은 그러한 기회를 제공하며 필요에 따라 점점 더 최적의 솔루션으로 반복 할 수 있습니다. 이러한 설계는 대용량 메모리 용으로 설계되었습니다 *.

* 성능이 중요한 영역에서 오랫동안 작업하면 데이터 유형 및 데이터 구조에 대한 관점이 바뀌고 메모리에 연결되는 방식을 보는 경향이 있으므로 데이터가 아닌 메모리에 중점을 둡니다 . 이진 검색 트리는 더 이상 고정 할당자가 지원하지 않는 한 트리 노드에 대해 불분명하고 캐시에 친숙하지 않은 메모리 청크와 같은 경우 로그 복잡성에만 더 이상 영향을 미치지 않습니다. 뷰는 알고리즘 복잡성을 무시하지 않지만 더 이상 메모리 레이아웃과 독립적으로 보이지 않습니다. 또한 작업 반복이 메모리 액세스 반복에 대한 것으로 간주되기 시작합니다. *

많은 성능이 중요한 디자인은 실제로 사람이 이해하고 사용하기 쉬운 고급 인터페이스 디자인의 개념과 매우 호환 될 수 있습니다. 차이점은 이 맥락에서 "높은 수준" 은 메모리 대량 수집, 잠재적으로 대규모 데이터 수집을 위해 모델링 된 인터페이스 및 상당히 낮은 수준 일 수있는 실제 구현에 관한 것입니다. 시각적 비유는 소리의 속도로 진행하는 동안 정말 편안하고 운전하기 쉽고 다루기 쉽고 매우 안전한 자동차 일 수 있지만 후드를 터뜨리면 내부에 불을 내뿜는 악마가 거의 없습니다.

더 거칠게 디자인하면 코드에서 더 효율적인 잠금 패턴을 제공하고 병렬 처리를 쉽게 이용할 수있는 더 쉬운 방법을 찾는 경향이 있습니다 (멀티 스레딩은 여기서 건너 뛸 수있는 철저한 주제입니다).

메모리 풀

지연 시간이 짧은 프로그래밍의 중요한 측면은 메모리의 할당 및 할당 해제의 일반적인 속도뿐만 아니라 참조의 지역성을 향상시키기 위해 메모리를 매우 명시 적으로 제어하는 ​​것입니다. 커스텀 할당 자 풀링 메모리는 실제로 우리가 설명한 것과 같은 종류의 디자인 사고 방식을 반영합니다. 대량으로 설계되었습니다 . 거친 수준으로 설계되었습니다. 메모리를 큰 블록으로 미리 할당하고 이미 작은 할당 단위로 할당 된 메모리를 풀링합니다.

이 아이디어는 비용이 많이 드는 것들 (예를 들어 범용 할당 자에 대한 메모리 청크 할당)을 더 거칠고 더 거친 수준으로 푸시하는 것과 동일합니다. 메모리 풀은 대량 으로 메모리를 처리하도록 설계되었습니다 .

타입 시스템 분리 메모리

모든 언어에서 세분화 된 객체 지향 디자인의 어려움 중 하나는 종종 많은 사용자 정의 유형 및 데이터 구조를 도입하려고한다는 것입니다. 이러한 유형은 동적으로 할당 된 경우 작은 청크 단위로 할당 할 수 있습니다.

C ++의 일반적인 예는 다형성이 필요한 경우이며, 일반적인 유혹은 범용 메모리 할당 자에 대해 서브 클래스의 각 인스턴스를 할당하는 것입니다.

결과적으로 연속적인 메모리 레이아웃을 약간의 비트 비트와 어드레싱 범위에 흩어져있는 조각으로 분리하여 더 많은 페이지 오류와 캐시 누락을 초래합니다.

지연 시간이 가장 짧고 끊김없는 결정적인 응답이 필요한 필드는 핫스팟이 항상 단일 병목 현상으로 끝나지 않는 곳일 수 있습니다. 작은 비 효율성이 실제로 실제로 "누적"일 수 있습니다 (많은 사람들이 상상하는 것) 프로파일 러에서 잘못 확인하여 검사를 유지하지만 대기 시간 기반 필드에서는 실제로 작은 비효율이 누적되는 드문 경우가 있습니다. 그리고 그러한 축적의 가장 일반적인 이유는 다음과 같습니다. 처음에 작은 덩어리의 메모리를 과도하게 할당합니다.

Java와 같은 언어에서는 가능하지 않은 배열 int(그러나 여전히 큰 고수준 인터페이스 뒤에 있음 )과 같은 병목 현상이 많은 영역 (긴밀한 루프로 처리됨)에 대해 더 많은 일반 오래된 데이터 유형의 배열을 사용하는 것이 도움이 될 수 있습니다 . , ArrayList사용자 정의의 Integer개체. 이것은 일반적으로 후자의 메모리 분리를 피합니다. C ++에서는 메모리 정의 패턴이 효율적인 경우 사용자 정의 유형을 연속적으로 거기에서 일반 컨테이너의 컨텍스트로 할당 할 수 있으므로 구조를 크게 저하시키지 않아도됩니다.

메모리를 다시 융합

여기서 해결책은 동종 데이터 유형에 대한, 그리고 심지어 동종 데이터 유형에 대한 사용자 지정 할당기에 도달하는 것입니다. 작은 데이터 유형과 데이터 구조가 메모리의 비트와 바이트로 평탄화 될 때, 동종의 특성을 갖습니다 (다양한 정렬 요구 사항이 있음에도 불구하고). 메모리 중심 사고 방식에서 그것들을 보지 않으면, 프로그래밍 언어의 타입 시스템은 잠재적으로 인접한 메모리 영역을 작은 작은 산란 덩어리로 분리 / 분리하기 위해 "원한다".

스택은이 메모리 중심 초점을 사용하여이를 피하고 사용자 정의 유형 인스턴스의 가능한 혼합 조합을 잠재적으로 저장할 수 있습니다. 스택을 최대한 활용하는 것이 가능할 때 최상의 아이디어는 거의 항상 캐시 라인에 있기 때문에 LIFO 패턴없이 이러한 특성 중 일부를 모방하는 메모리 할당자를 설계 할 수 있습니다. 더 복잡한 메모리 할당 및 할당 해제 패턴을위한 청크

최신 하드웨어는 인접한 메모리 블록을 처리 할 때 최고점에 있도록 설계되었습니다 (예 : 동일한 캐시 라인, 같은 페이지에 반복적으로 액세스). 키워드는 연속성이 있습니다. 관심있는 주변 데이터가있는 경우에만 유용합니다. 따라서 성능의 많은 핵심 (아직 어려움)은 분리 된 메모리 덩어리를 다시 제거하기 전에 전체 (모든 주변 데이터가 관련됨)로 액세스되는 연속 블록으로 다시 통합하는 것입니다. 프로그래밍 언어에서 특히 사용자 정의 유형의 풍부한 유형 시스템이 여기에서 가장 큰 장애물이 될 수 있지만 적절한 경우 사용자 지정 할당 기 및 / 또는 부피가 큰 디자인을 통해 항상 문제를 해결하고 해결할 수 있습니다.

추한

"추악한"은 말하기 어렵다. 그것은 주관적인 지표이며, 성능이 매우 중요한 분야에서 일하는 사람은 "아름다움"에 대한 아이디어를 훨씬 더 데이터 지향적이고 대량으로 처리하는 인터페이스에 중점을 둔 아이디어로 변경하기 시작할 것입니다.

위험한

"위험"이 더 쉬울 수 있습니다. 일반적으로 성능은 하위 수준 코드에 도달하려는 경향이 있습니다. 예를 들어, 메모리 할당자를 구현하는 것은 데이터 유형 아래에 도달하지 않고 위험한 수준의 원시 비트 및 바이트에서 작업하지 않으면 불가능합니다. 결과적으로 이러한 성능이 중요한 하위 시스템에서 신중한 테스트 절차에 중점을 두어 최적화 수준을 적용하여 테스트의 철저 성을 확장 할 수 있습니다.

아름다움

그러나이 모든 것은 구현 세부 사항 수준에 있습니다. 베테랑 대규모의 성능 중심적인 사고 방식에서 "아름다움"은 구현 세부 사항이 아닌 인터페이스 디자인으로 이동하는 경향이 있습니다. 인터페이스 설계 변경시 발생할 수있는 결합 및 계단식 손상으로 인해 구현보다 "아름답고"사용 가능하며 안전하며 효율적인 인터페이스를 찾는 것이 기하 급수적으로 높은 우선 순위가됩니다. 구현은 언제든지 교체 할 수 있습니다. 우리는 일반적으로 필요에 따라 측정에서 지적한대로 성능을 반복합니다. 인터페이스 디자인의 핵심은 전체 시스템을 손상시키지 않고 이러한 반복을위한 공간을 확보 할 수있을 정도로 거칠게 모델링하는 것입니다.

실제로, 성능이 중요한 개발에 대한 베테랑의 초점은 종종 안전, 테스트, 유지 관리 성, SE의 제자에 주로 초점을 두는 경향이 있습니다. 중요한 서브 시스템 (입자 시스템, 이미지 처리 알고리즘, 비디오 처리, 오디오 피드백, 레이 트레이서, 메시 엔진 등)은 유지 관리의 악몽에 빠지지 않도록 소프트웨어 엔지니어링에 세심한주의를 기울여야합니다. 우연히도 가장 놀랍도록 효율적인 제품은 버그 수가 가장 적을 수 있습니다.

TL; DR

어쨌든, 그것은 진정으로 성능에 중요한 분야의 우선 순위, 대기 시간을 줄이고 작은 비 효율성을 축적시킬 수있는 것, 실제로 "아름다움"을 구성하는 것 (가장 생산적으로 보는 것)에 이르기까지 주제에 대한 나의 취재입니다.


0

다르지 않지만 여기에 내가하는 일이 있습니다.

  1. 깨끗하고 유지 보수가 가능하도록 작성하십시오.

  2. 수행 성능 진단을 , 그리고 당신을 알려줍니다 문제, 당신은 생각하지 않는 사람을 고정합니다. 보장, 그들은 당신이 기대하는 것과 다를 것입니다.

이러한 수정은 여전히 ​​명확하고 유지 관리 가능한 방식으로 수행 할 수 있지만 코드를 보는 사람들이 왜 그렇게했는지 알 수 있도록 주석을 추가해야합니다. 그렇지 않으면 취소합니다.

트레이드 오프가 있습니까? 나는 그렇게 생각하지 않습니다.


0

매우 빠른 추악한 코드를 작성하고 추한 코드만큼 빠른 아름다운 코드를 작성할 수도 있습니다. 병목 현상은 코드의 아름다움 / 조직 / 구조가 아니라 선택한 기술에 있습니다. 예를 들어, 비 차단 소켓을 사용하고 있습니까? 단일 스레드 디자인을 사용하고 있습니까? 스레드 간 통신에 잠금없는 큐를 사용하고 있습니까? GC를 위해 쓰레기를 생산하고 있습니까? 중요한 스레드에서 차단 I / O 작업을 수행하고 있습니까? 보시다시피 이것은 아름다움과 관련이 없습니다.


0

최종 사용자에게 중요한 것은 무엇입니까?

  • 공연
  • 특징 / 기능
  • 디자인

사례 1 : 최적화 된 불량 코드

  • 어려운 정비
  • 오픈 소스 프로젝트 인 경우 거의 읽을 수 없음

사례 2 : 최적화되지 않은 양호한 코드

  • 손쉬운 유지 보수
  • 나쁜 사용자 경험

해결책?

쉽고 중요한 성능 핵심 코드

예 :

5 가지 방법으로 구성된 프로그램 , 그중 3 가지 방법은 데이터 관리 용, 1 개는 디스크 읽기 용, 다른 하나는 디스크 쓰기 용

이 3 가지 데이터 관리 방법은 두 가지 I / O 방법을 사용하며 이에 의존합니다

우리는 I / O 방법을 최적화 할 것입니다.

이유 : I / O 메서드는 변경 될 가능성이 적고 앱의 디자인에 영향을 미치며, 그 결과 프로그램의 모든 것이 그에 따라 달라 지므로 성능이 중요해 보이므로 최적화하기 위해 모든 코드를 사용합니다. .

즉, 코드의 특정 부분을 최적화하여 프로그램을 신속하게 유지하면서 우수한 코드와 관리 가능한 프로그램 설계를 얻을 수 있습니다.

내가 생각하고..

코드가 잘못되면 인간이 연마를 최적화하기가 어렵고 작은 실수로 인해 코드가 더 나빠질 수 있으므로 초보자 / 초보자를위한 좋은 코드는 못생긴 코드를 잘 작성하면 더 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.