코드 작성 방법의 점진적인 변화가 시스템 성능에 영향을 미쳤습니까? 내가 신경 써야 할까?


35

TD; DR :

내가 묻는 것에 대해 약간의 혼란이 있었으므로 여기에 질문의 원동력이 있습니다.

나는 항상 그 질문이 무엇인지 생각했습니다. 원래 잘 표현하지 않았을 수도 있습니다. 그러나 의도는 항상 " 모 놀리 식 단일 단위, 한 곳에서 모든 것을 수행하는 것, 하나의 파일, 단단히 결합 된 "코드 보다 본질적으로 느리게 모듈화 된, 분리 된, 느슨하게 결합 된, 분리 된, 리팩터링 코드입니다. 나머지는 내가 그 당시 나 지금이나 나중에 나올 세부 사항과 다양한 증상입니다. 어떤 규모에서는 확실히 느립니다. 조각 모음되지 않은 디스크와 마찬가지로 모든 곳에서 조각을 가져와야합니다. 더 느립니다. 확실 해요 하지만 걱정해야합니까?

그리고 질문은 ...에 관한 것이 아닙니다.

마이크로 최적화, 조기 최적화 등에 관한 것이 아닙니다. "이 부분이나 그 부분을 죽일 정도로 최적화"하는 것이 아닙니다.

그때는 무엇입니까?

시간이 지남에 따라 등장한 코드 작성 에 대한 전반적인 방법론과 기술 및 사고 방식에 관한 것입니다.

  • "이 코드를 의존성으로 클래스에 삽입하십시오"
  • "클래스 당 하나의 파일 작성"
  • "데이터베이스, 컨트롤러, 도메인에서보기를 분리하십시오".
  • 스파게티 균질 단일 코드 블록을 작성하지 말고 함께 작동하는 많은 개별 모듈 구성 요소를 작성하십시오.

그것은 현재 10 년 안에 대부분의 프레임 워크에서 보여지고 옹호되고 컨벤션을 옹호하며 커뮤니티를 통해 전달되는 코드의 방식과 스타일에 관한 것입니다. '모 놀리 식 블록'에서 '마이크로 서비스'로의 사고의 전환입니다. 기계 수준의 성능과 오버 헤드, 프로그래머 수준의 오버 헤드 측면에서 가격이 책정됩니다.

원래 질문은 다음과 같습니다.

컴퓨터 과학 분야에서 나는 프로그래밍에 관한 생각에서 주목할만한 변화를 발견했습니다. 나는 다음과 같은 조언을 자주 받는다.

  • 더 작은 기능별 코드 작성 (이 방법으로 테스트 및 유지 관리 가능)
  • 대부분의 메소드 / 함수가 몇 줄에 불과할 때까지 기존 코드를 더 작은 코드 조각으로 리팩토링하고 목적이 무엇인지 명확합니다 (더 큰 모 놀리 식 블록에 비해 더 많은 함수를 생성 함)
  • 관심사 분리 등 하나만 수행하는 함수 작성 (보통 스택에 더 많은 함수와 더 많은 프레임을 작성 함)
  • 더 많은 파일 생성 (파일 당 하나의 클래스, 분해 목적의 MVC, 도메인 아키텍처, 디자인 패턴, OO 등의 레이어 목적으로 더 많은 파일 시스템 호출을 생성하는 클래스)

이것은 2500 줄에 걸친 메소드와 모든 클래스와 신 객체를 사용하는 "오래된"또는 "오래된"또는 "스파게티"코딩 방식과 비교하여 변경된 것입니다.

내 질문은 이것입니다 :

기계 코드, 1 초 및 0 초, 조립 지침, HDD 플래터에 이르기까지 다양한 리팩토링 된 작고 작은 함수와 메소드가있는 완벽하게 클래스로 분리 된 OO 코드가 생성되는 것에 대해 걱정해야합니다. 더 많은 오버 헤드?

세부

OO 코드와 메소드 호출이 결국 ASM에서 처리되는 방식과 DB 호출 및 컴파일러 호출이 HDD 플래터에서 움직이는 액추에이터 암으로 변환되는 방식에 대해 친숙하지는 않지만 몇 가지 아이디어가 있습니다. 각 추가 함수 호출, 객체 호출 또는 "#include"호출 (일부 언어)은 추가 명령어 세트를 생성 하여 실제 "유용한"코드를 추가하지 않고 코드 볼륨을 늘리고 다양한 "코드 배선"오버 헤드를 추가한다고 가정합니다. . 또한 실제로 하드웨어에서 실행되기 전에 ASM에 대한 최적화를 수행 할 수 있다고 생각하지만 최적화도 그렇게 많이 할 수 있습니다.

따라서 제 질문은 잘 분리 된 코드 (수백 개의 파일, 클래스 및 디자인 패턴 등으로 분리 된 코드)가 실제로 얼마나 많은 오버 헤드 (공간 및 속도)를 포함하는지는 이 오버 헤드로 인해 하나의 모 놀리 식 파일의 모든 것 "

명확성을 위해 업데이트 :

나는 동일한 코드를 가져 와서 나누고, 리팩토링하고, 점점 더 많은 함수와 객체 및 메소드와 클래스로 분리 하여 더 작은 코드 조각 사이에 점점 더 많은 매개 변수가 전달 될 것이라고 가정 합니다. 확실히, 리팩토링 코드는 스레드를 계속 유지해야하며 매개 변수 전달이 필요합니다. 이상의 방법 이상의 클래스 이상의 공장 메소드 디자인 패턴, 더욱 오버 헤드 정보의 다양한 비트를 전달 결과 는 단일 모 놀리 식 클래스 또는 방법의 경우보다.

모든 코드의 최대 70 %가 ASM의 MOV 명령으로 구성되어 있으며 실제 계산이 아닌 적절한 변수로 CPU 레지스터를로드한다고합니다. 제 경우에는 PUSH / POP 명령으로 CPU 시간을로드하여 다양한 코드 조각 사이에 링크 및 매개 변수 전달을 제공합니다. 코드를 작게 만들수록 더 많은 오버 헤드 "연결"이 필요합니다. 이 연결이 소프트웨어 팽창 및 속도 저하에 추가 될까 걱정하고 다음 세기에 소프트웨어를 구축하는 현재 및 미래 세대의 프로그래머 때문에이 문제에 대해 걱정해야하는지, 그리고 어느 정도가 필요한지 궁금합니다. 이러한 관행에 따라 구축 된 소프트웨어와 함께 생활하고 소비해야합니다.

업데이트 : 여러 파일

오래된 코드를 천천히 대체하는 새 코드를 작성 중입니다. 특히 나는 이전 클래스 중 하나가 ~ 3000 줄 파일이라고 언급했습니다 (앞서 언급했듯이). 이제 테스트 파일을 포함하여 여러 디렉토리에 위치한 15-20 파일 세트가되고 일부를 함께 묶는 데 사용하는 PHP 프레임 워크는 포함하지 않습니다. 더 많은 파일도 제공됩니다. 디스크 I / O와 관련하여 여러 파일을로드하는 것은 하나의 큰 파일을로드하는 것보다 느립니다. 물론 모든 파일이로드되는 것은 아니며 필요에 따라로드되며 디스크 캐싱 및 메모리 캐싱 옵션이 존재하지만 여전히 메모리 loading multiple files보다 더 많은 처리가 필요 하다고 생각합니다 loading a single file. 나는 내 관심사에 그것을 추가하고 있습니다.

업데이트 : 종속성 모든 것을 주입하십시오.

잠시 후에 다시 돌아옵니다. 내 질문이 잘못 이해 된 것 같습니다. 아니면 일부 답변을 오해하기로 선택했을 수도 있습니다. 나는 약간의 답변이 지적되었으므로 마이크로 최적화에 대해 이야기하고 있지 않습니다 (적어도 나는 마이크로 최적화에 대해 말하는 것을 잘못 생각합니다). 코드의 모든 수준에서 나는 최근에 Zend Con에서이 스타일의 코드가 컨벤션의 핵심 요점 중 하나였습니다. 보기에서 논리를 분리하고, 모델에서 보거나, 데이터베이스에서 모델을, 가능하면 데이터베이스에서 데이터를 분리하십시오. 의존성-모든 것을 주입하십시오. 때로는 아무것도 하지 않는 배선 코드 (함수, 클래스, 상용구)를 추가하는 것을 의미합니다.하지만 이음매 / 후크 포인트 역할을하며 대부분의 경우 코드 크기를 쉽게 두 배로 늘립니다.

업데이트 2 : "코드를 더 많은 파일로 분리"가 성능에 크게 영향을 미치나요 (모든 수준의 컴퓨팅에서)

compartmentalize your code into multiple files오늘날의 컴퓨팅 (성능, 디스크 사용률, 메모리 관리, CPU 처리 작업) 에 대한 철학은 어떤 영향을 미칩니 까?

나는 말하고있다

전에...

가상의 아직까지는 그리 멀지 않은 과거에 모델과 뷰, 컨트롤러 스파게티가 있거나 스파게티가 아닌 파일의 단일 블록을 쉽게 작성할 수 있지만 이미로드 된 후에는 모든 것을 실행 합니다. 과거에 C 코드를 사용하여 일부 벤치 마크를 수행하면 단일 900Mb 파일을 메모리에로드하고 큰 덩어리로 처리하는 것이 작은 파일을로드하고 더 작은 평화 식사로 처리하는 것보다 훨씬 빠릅니다. 결국 동일한 작업을 수행하는 덩어리.

.. 그리고 지금*

오늘 나는 원장을 보여주는 코드를 찾고 있습니다. .. 항목이 "주문"이면 주문 HTML 블록을 표시하십시오. 광고 항목을 복사 할 수있는 경우 아이콘과 그 뒤에 HTML 매개 변수를 표시하는 HTML 블록을 인쇄하면 복사 할 수 있습니다. 항목을 위나 아래로 이동할 수 있으면 적절한 HTML 화살표를 표시하십시오. 기타 Zend Framework를 통해partial()본질적으로 "매개 변수를 가져 와서 호출하는 별도의 HTML 파일에 삽입하는 함수 호출"을 의미합니다. 원하는 세부 정보에 따라 원장의 가장 작은 부분에 대해 별도의 HTML 함수를 만들 수 있습니다. 하나는 화살표 위, 아래 화살표, 하나는 "이 항목을 복사 할 수 있습니다"등입니다. 웹 페이지의 작은 부분을 표시하기 위해 여러 파일을 쉽게 만들 수 있습니다. 내 코드와 비하인드 젠드 프레임 워크 코드를 사용하면 시스템 / 스택은 20-30 개의 서로 다른 파일을 호출 할 수 있습니다.

뭐?

코드를 여러 개의 작은 개별 파일로 분할하여 생성되는 시스템 의 마모에 관심이 있습니다.

예를 들어, 더 많은 파일을로드한다는 것은 파일 시스템의 다양한 위치와 실제 HDD의 다양한 위치에 파일을 배치하는 것을 의미합니다. 이는 더 많은 HDD 탐색 및 읽기 시간을 의미합니다.

CPU의 경우 더 많은 컨텍스트 전환 및 다양한 레지스터로드를 의미합니다.

이 하위 블록 (업데이트 # 2)에서는 여러 파일을 사용하여 단일 파일에서 수행 할 수있는 동일한 작업을 수행하여 시스템 성능에 영향을주는 방법에 대해 더 자세히 관심이 있습니다.

Zend Form API와 간단한 HTML 사용

Zend Form API를 최신의 최신 OO 사례와 함께 사용하여 유효성 검사를 통해 HTML 양식을 작성하고 POST도메인 객체로 변환 했습니다.

그것을 만드는 데 35 파일이 필요했습니다.

35 files = 
    = 10 fieldsets x {programmatic fieldset + fieldset manager + view template} 
    + a few supporting files

이 파일들은 모두 간단한 HTML + PHP + JS + CSS 파일로 대체 될 수 있으며, 총 4 개의 경량 파일 일 수 있습니다.

더 낫습니까? 그만한 가치가 있나요? ... 35 개의 파일과 수많은 Zend Zramework 라이브러리 파일, 4 개의 간단한 파일을로드한다고 상상해보십시오.


1
멋진 질문입니다. 나는 벤치마킹을 할 것입니다 (좋은 사례를 찾기 위해 하루 정도 걸립니다). 그러나이 정도의 속도 향상은 가독성 및 개발 비용에 막대한 비용이 듭니다. 내 초기 추측은 결과가 무시할만한 성능 향상이라는 것입니다.
Dan Sabin

7
@Dan : 1, 5, 10 년 동안 유지 보수 한 후 코드를 벤치마킹하기 위해 달력에 넣을 수 있습니까? 내가 기억한다면 나는 결과를 다시 확인할 것이다 :)
mattnz

1
그래, 진짜 키 커야 우리 모두는 조회를 줄이고 함수 호출이 더 빠르다는 데 동의합니다. 그러나 새 팀원을 유지 관리하고 쉽게 훈련시키는 것과 같은 것이 선호되는 경우를 상상할 수 없습니다.
Dan Sabin '28

2
명확히하기 위해 프로젝트의 특정 속도 요구 사항이 있습니다. 아니면 코드가 "빠르게"가고 싶습니까? 후자가 걱정하지 않는다면 충분히 빠르지 만 유지하기 쉬운 코드는 빠르지 만 엉망인 코드보다 훨씬 낫습니다.
Cormac Mulhall 12

4
성능상의 이유로 함수 호출을 피한다는 아이디어는 Dijkstra가 조기 최적화에 대한 유명한 인용문에서 난처한 미친 생각입니다. 진심으로, 난 할 수 없어
RibaldEddie

답변:


10

내 질문은 이것입니다 : 호출이 기계 코드, 1 및 0, 어셈블리 명령으로 내려갈 때 다양한 작고 작은 기능을 가진 클래스로 분리 된 코드가 너무 많은 오버 헤드를 생성해야한다고 걱정해야합니까?

내 대답은 그렇습니다. 작은 함수가 많기 때문이 아닙니다 (한 번에 함수 호출의 오버 헤드가 상당히 중요하고 루프에서 백만 번의 작은 호출을 수행하여 프로그램 속도를 늦출 수는 있지만 오늘날 컴파일러는 함수를 인라인하고 남은 것을 가져옵니다. CPU 팬시 예측 알고리즘에 의해 처리되므로 걱정하지 마십시오.) 기능이 너무 작아서 머리에 들어 가지 않을 때 프로그램에 너무 많은 레이어링 개념을 도입하기 때문입니다. 더 큰 구성 요소를 사용하는 경우 동일한 작업을 반복해서 수행하지 않는다는 것을 합리적으로 확신 할 수 있지만 프로그램을 아주 세분화하여 호출 경로를 실제로 이해하지 못하고 결국에는 무언가로 끝날 수 있습니다 거의 작동하지 않으며 유지 관리가 거의 불가능합니다.

예를 들어, 1 가지 방법으로 웹 서비스에 대한 참조 프로젝트를 보여준 곳에서 근무했습니다. 이 프로젝트는 단일 웹 서비스를위한 32 개의 .cs 파일로 구성되었습니다! 전체 시스템을 설명 할 때 각 부분이 작고 이해하기 쉽더라도 이것이 너무 복잡하다는 것을 알았습니다. 전체 시스템을 설명 할 때 나는 지옥이 무엇을하고 있는지 알기 위해 전화를 통해 추적해야한다는 것을 알았습니다. 예상대로 너무 많은 추상화가 포함되었습니다). 대체 웹 서비스는 4 .cs 파일이었습니다.

나는 거의 대체로 같았을 것이라고 생각하면서 성능을 측정하지는 않았지만 유지 관리가 훨씬 저렴하다는 것을 보장 할 수 있습니다. 모두가 프로그래머 시간이 CPU 시간보다 중요하다는 이야기를 할 때 개발자와 유지 보수 모두에서 프로그래머 시간이 많이 걸리는 복잡한 괴물을 만들면 나쁜 행동에 대한 변명을하고 있는지 궁금합니다.

모든 코드의 최대 70 %가 ASM의 MOV 명령으로 구성되어 있으며 실제 계산이 아닌 적절한 변수로 CPU 레지스터를로드한다고합니다.

되어 CPU가 생각하는 일, 그들은 레지스터에 메모리에서 비트를 이동, 추가하거나 뺄하고 메모리에 다시 넣어. 모든 컴퓨팅은 그 정도로 요약됩니다. 한 번 스레드 코드에서 작업하는 것보다 컨텍스트 전환 (예 : 스레드의 레지스터 상태 저장 및 복원)에 대부분의 시간을 소비하는 매우 다중 스레드 프로그램이있었습니다. 잘못된 장소의 간단한 잠금 장치는 실제로 성능을 망쳐 놓았으며 너무나도 무해한 코드였습니다.

그래서 내 충고는 : 코드가 다른 사람에게 잘 보이도록 극단적 인 중간 지점을 찾고 시스템이 제대로 작동하는지 테스트하십시오. OS 기능을 사용하여 CPU, 메모리, 디스크 및 네트워크 IO에서 예상대로 작동하는지 확인하십시오.


나는 이것이 지금 가장 많이 말하는 것 같아요. 중간 정도의 좋은 근거는 난해한 코드 분해 및 견과에 묶이지 않고 특정 개념 (DI와 같은)을 따르고 사용하는 동안 코드 조각에 대한 생각을 나누는 개념부터 시작하는 것입니다. 또는 아닙니다).
Dennis

1
개인적으로, 더 많은 ""현대 ""코드는 프로파일 링이 다소 쉽다는 것을 알았습니다 ... 코드를 유지 관리하기가 더 편할수록 프로파일 링이 더 쉽다고 생각하지만 한계가 있습니다. 덜 유지 보수 ...
AK_

25

세심한주의를 기울이지 않으면 이러한 문제와 같은 미세 최적화는 유지 관리 할 수없는 코드로 이어집니다.

처음에는 좋은 생각처럼 보입니다. 프로파일 러는 코드가 더 빠르며 V & V / Test / QA에서도 작동한다고 말합니다. 곧 버그가 발견되고 고려되지 않은 요구 사항 변경 및 개선 사항이 요구됩니다.

프로젝트 코드 수명 동안 성능이 저하되고 효율성이 떨어집니다. 유지 관리 가능한 코드는 유지 관리가 불가능한 코드보다 성능이 저하되므로 속도가 느려집니다. 이유는 코드가 변경 될 때 엔트로피를 빌드하기 때문입니다.

유지 불가능한 코드에는 더 많은 데드 코드, 중복 경로 및 복제가 있습니다. 이로 인해 더 많은 버그가 발생하여 성능을 포함한 코드 저하주기가 발생합니다. 오래지 않아 개발자는 자신이 변경 한 내용이 올바르다는 확신을 갖지 못합니다. 이것은 속도를 늦추고 조심스럽게 만들며 일반적으로 그들이 볼 수있는 세부 사항만을 다루기 때문에 훨씬 더 엔트로피로 이어집니다.

작은 모듈과 단위 테스트를 통해 유지 관리 가능한 코드를 쉽게 변경할 수 있으며 더 이상 필요없는 코드를 쉽게 식별하고 제거 할 수 있습니다. 고장난 코드는 식별하기 쉽고, 수리하거나 자신있게 교체 할 수 있습니다.

결국 수명주기 관리가 시작되고 "이보다 빠르므로 항상 빠릅니다."만큼 간단하지 않습니다.

무엇보다 느린 올바른 코드는 빠른 잘못된 코드보다 훨씬 빠릅니다.


고마워 이것을 내가 가고있는 곳으로 조금 돌리기 위해, 나는 마이크로 최적화에 대해 이야기하는 것이 아니라 더 작은 코드 작성, 더 많은 의존성 주입 및 더 많은 외부 기능 부분 및 일반적으로 더 많은 코드의 "이동 부분"을 통합하는 글로벌 이동 그들이 작동하려면 모든 것이 서로 연결되어 있어야합니다. 나는 이것이 하드웨어 수준에서 더 많은 연결 / 커넥터 / 변수 전달 / MOV / PUSH / POP / CALL / JMP 보풀을 생성한다고 생각하는 경향이 있습니다. 또한 "fluff"에 대한 하드웨어 수준 컴퓨팅주기를 희생시키면서 코드 가독성으로 전환 할 가치가 있다고 생각합니다.
Dennis

10
성능상의 이유로 함수 호출을 피하는 것은 마이크로 최적화입니다! 진심으로. 마이크로 최적화의 더 좋은 예를 생각할 수 없습니다. 성능 차이가 실제로 작성중인 소프트웨어 종류에 중요하다는 증거는 무엇입니까? 당신이없는 것 같습니다.
RibaldEddie

17

인라인으로 지적 할 때 C ++과 같은 낮은 수준의 코드 형식에서는 차이가 생길 수 있지만 CAN은 가볍게 말합니다.

웹 사이트에 요약하면 쉬운 답변이 없습니다 . 그것은 시스템에 달려 있고, 응용 프로그램이하는 일에 달려 있으며, 언어와 컴파일러와 최적화에 달려 있습니다.

예를 들어 C ++은 인라인으로 성능을 향상시킬 수 있습니다. 여러 번 그것은 아무것도하지 않거나 성능을 저하시킬 수 있지만 이야기를 들었지만 개인적으로 그런 경험을하지 못했습니다. 인라인은 컴파일러가 최적화하도록 제안하는 것에 지나지 않으며 무시할 수 있습니다.

더 높은 수준의 프로그램을 개발하는 경우, 시작할 프로그램이 하나라도 있어도 오버 헤드는 문제가되지 않습니다. 컴파일러는 요즘 매우 똑똑하고 어쨌든이 것들을 처리해야합니다. 많은 프로그래머들은 다음과 같은 코드를 사용하여 코드를 구현합니다. 컴파일러를 신뢰하지 마십시오. 이것이 당신에게 적용된다면, 당신이 중요하다고 생각하는 약간의 최적화조차도 될 수 있습니다. 그러나 모든 언어는 이와 관련하여 다릅니다. Java는 런타임시 자동으로 인라인 최적화를 수행합니다. Javascript에서는 웹 페이지의 인라인 (별도의 파일이 아님)이 향상되어 웹 페이지의 1 밀리 초마다 셀 수 있지만 IO 문제가 더 많습니다.

그러나 프로그래머가 C ++과 같은 많은 머신 코드 작업을 수행하는 하위 수준의 프로그램에서는 그 차이가 크게 달라질 수 있습니다. 게임은 특히 콘솔에서 CPU 파이프 라이닝이 중요한 위치에 대한 좋은 예이며 인라인과 같은 것이 여기 저기에 약간 더해질 수 있습니다.

특히 인라인에 대한 좋은 읽기 : http://www.gotw.ca/gotw/033.htm


내 질문의 관점에서, 나는 자체적으로 인라인에 초점을 맞추지 않고 다양한 코드 조각을 연결하는 CPU, 버스 및 I / O의 시간 프로세스를 차지하는 "코딩 된 배선"에 중점을 둡니다. 배선 코드의 50 % 이상과 실제 코드의 50 %가 실행하려는 지점이 있는지 궁금합니다. 나는 가장 엄격한 코드에도 쓸 수있는 많은 보풀이 있다고 생각하며 인생의 사실 인 것 같습니다. 비트 및 바이트 수준에서 실행되는 실제 코드의 대부분은 물류입니다. 한 곳에서 다른 곳으로 값을 이동하고 다른 곳으로 이동하며 때때로 추가하는 경우도 있습니다.
Dennis

... 빼기 또는 기타 비즈니스 관련 기능. 증가하는 변수에 할당 된 오버 헤드가 줄어들어 루프 언 롤링이 일부 루프의 속도를 높일 수있는 것처럼, 더 큰 함수를 작성하면 사용 사례가 설정되어있는 경우 속도가 추가 될 수 있습니다. 작은 코드 조각을 작성하고,이 배선을 늘리면서 가독성을 높이는 데 도움이되고 (소망 적으로) 마이크로 레벨에서 부풀어 오름을 피하는 데 도움이되는 충고가 많을수록 전체적인 관심이 더 커집니다.
Dennis

3
@Dennis-고려해야 할 한 가지는 OO 언어에서 프로그래머가 쓰는 것 (a + b)과 생성되는 코드 (두 개의 레지스터를 간단하게 추가하는 것, 메모리에서 먼저 이동합니까? 함수는 객체의 operator +?를 호출합니다. 따라서 프로그래머 수준의 '작은 기능'은 한 번 머신 코드로 렌더링 된 것 이외의 작은 것일 수 있습니다.
Michael Kohne

2
@Dennis Windows 용 ASM 코드 (직접 컴파일되지 않은)를 작성하는 것은 "mov, mov, invoke, mov, mov, invoke"의 행을 따른다고 말할 수 있습니다. 호출은 푸시 / 팝으로 래핑 된 호출을 수행하는 매크로가됩니다. 때때로 자신의 코드로 함수 호출을 수행하지만 모든 OS 호출로 인해 드워프됩니다.
Brian Knoblauch

12

이것은 2500 줄에 걸쳐있는 메소드가 있고 큰 클래스가 모든 것을 수행하는 "오래된"또는 "나쁜"코드 사례와 비교하여 변경된 것입니다.

나는 누군가가 그렇게하는 것이 좋은 습관이라고 생각하지 않습니다. 그리고 나는 성능상의 이유로 그것을 한 사람들을 의심합니다.

도널드 크 누스의 유명한 인용문은 여기에 매우 관련이 있다고 생각합니다.

우리는 시간의 97 % 정도라는 작은 효율성을 잊어야합니다. 조기 최적화는 모든 악의 근원입니다.

따라서 코드의 97 %에서 모범 사례를 사용하고 작은 방법을 작성하십시오 (소규모가 작은 것, 모든 방법이 단지 몇 줄이 아니라고 생각합니다) 등. 나머지 3 %의 경우 성능 상관없이 측정 하십시오. 측정 결과 작은 방법이 많을수록 실제로 코드 속도가 크게 느려지는 것으로 나타나면 큰 방법으로 결합해야합니다. 그러나 유지 관리가 불가능한 코드 더 빠를 있으므로 작성하지 마십시오 .


11

숙련 된 프로그래머와 현재의 생각에 귀를 기울여야합니다. 수년간 대규모 소프트웨어를 다루는 사람들은 기여할 ​​무언가가 있습니다.

내 경험에 따르면 여기에 속도 저하가 발생하고 그 크기는 작지 않습니다. 그것들은 큰 순서입니다.

  • 모든 코드 줄이 다른 코드 줄보다 대략 많은 시간이 걸린다는 가정. 예를 들어 cout << endla = b + c. 전자는 후자보다 수천 배 더 오래 걸립니다. Stackexchange는 "이 코드를 최적화하기 위해 여러 가지 방법을 시도했지만 차이가없는 것 같습니다."라는 형식의 질문이 많이 있습니다. 중간에 큰 함수 호출이있을 때.

  • 일단 작성된 함수 또는 메소드 호출은 물론 필요하다는 가정입니다. 함수와 메소드는 호출하기 쉽고 호출은 일반적으로 매우 효율적입니다. 문제는 신용 카드와 같습니다. 그들은 당신이 정말로 원하는 것보다 더 많이 소비하도록 유혹하고, 당신이 소비 한 것을 숨기는 경향이 있습니다. 게다가 대형 소프트웨어에는 추상화 계층에 계층이 있으므로 각 계층에 15 % 만 낭비하더라도 5 개 이상의 계층은 2의 속도 저하 요인이됩니다. 이에 대한 답은 기능을 제거하거나 쓰지 않는 것입니다 더 큰 기능을 위해서는 스스로이 문제를 경계하고 이를 기꺼이 근절 할 수 있도록 훈련 해야합니다 .

  • 질주 일반. 추상화의 가치는 적은 코드로 더 많은 일을 할 수있게하는 것입니다. 적어도 그것이 희망입니다. 이 아이디어는 극단적으로 추진 될 수 있습니다. 일반성이 너무 큰 문제는 모든 문제가 구체적이며 일반적인 추상화로 문제를 해결할 때 해당 추상화가 문제의 특정 속성을 활용할 수있는 것은 아닙니다. 예를 들어, 길이가 3을 초과하지 않을 때 큰 크기에서 효율적일 수있는 고급 우선 순위 큐 클래스가 사용 된 상황을 보았습니다!

  • 질주하는 데이터 구조. OOP는 매우 유용한 패러다임이지만 데이터 구조를 최소화하도록 권장하지는 않습니다. 오히려 데이터 구조의 복잡성을 숨기도록 권장합니다. 예를 들어, 데이텀 A가 어떤 식 으로든 수정되면 A가 알림 이벤트를 발행하여 B와 C가 전체 앙상블의 일관성을 유지하도록 자체적으로 수정할 수있는 "알림"개념이 있습니다. 이것은 많은 레이어에 전파 될 수 있고 수정 비용을 엄청나게 확대 할 수 있습니다. 그러면 A 로의 변경이 곧 취소 될 수 있습니다.앙상블의 일관성을 유지하기 위해 노력한 노력이 다시 한 번 수행되어야 함을 의미하는 또 다른 수정으로 변경되었습니다. 혼란스러운 것은 이러한 모든 알림 처리기의 버그 가능성 및 순환 성 등입니다. 데이터 구조를 표준화 된 상태로 유지하는 것이 훨씬 좋습니다. 따라서 한 곳에서만 변경해야합니다. 정규화되지 않은 데이터를 피할 수없는 경우 짧은 가죽 끈으로 일관성을 유지하는 것보다 불일치를 복구하기 위해 정기적 인 패스를 사용하는 것이 좋습니다.

... 더 많은 것을 생각하면 추가하겠습니다.


8

짧은 대답은 "예"입니다. 그리고 일반적으로 코드가 약간 느려집니다.

그러나 때로는 적절한 OO-ish 리팩토링으로 코드를 더 빠르게 만드는 최적화가 드러날 것입니다. 복잡한 중첩 된 객체 배열 대신 적절한 데이터 구조, 게터 등을 사용하여 복잡한 Java 알고리즘을 훨씬 더 OO-ish 한 한 프로젝트에서 작업했습니다. 그러나 데이터 구조에 대한 액세스를보다 효율적으로 격리하고 제한함으로써 비어있는 결과에는 null이있는 거대한 Doubles 배열에서 비어있는 결과에는 NaN이있는보다 체계적인 Double 배열로 변경할 수있었습니다. 이로 인해 속도가 10 배 증가했습니다.

부록 : 일반적으로 더 작고 더 나은 구조화 된 코드는 멀티 스레딩에 더 적합해야하며, 주요 속도를 높이는 가장 좋은 방법입니다.


1
Doubles 에서 s로 전환 double해야 더 나은 구조화 된 코드가 필요한지 알 수 없습니다 .
svick

와우, 공감대? 원래 클라이언트 코드는 Double.NaN을 처리하지 않았지만 빈 값을 나타내는 null을 확인했습니다. 재구성 후에는 다양한 알고리즘 결과의 getter로 캡슐화를 통해이를 처리 할 수있었습니다. 물론 클라이언트 코드를 다시 작성할 수 있었지만 더 쉬웠습니다.
user949300

기록을 위해, 나는이 답변을 하향 투표 한 사람이 아니었다.
svick

7

무엇보다도 프로그래밍은 트레이드 오프에 관한 것 입니다. 이 사실에 근거하여, 나는 예라고 대답하도록 기울 입니다. 느려질 수 있습니다 . 그러나 당신이 얻는 것에 대해 생각하십시오. 읽을 수 있고 재사용 가능하며 쉽게 수정할 수있는 코드를 얻는 것은 가능한 모든 단점을 능가합니다.

@ user949300에서 언급했듯이 , 이러한 접근 방식으로 알고리즘 또는 아키텍처 적으로 개선 할 수있는 영역을 쉽게 발견 할 수 있습니다. 그것들을 개선하는 것은 일반적으로 가능한 OO 또는 함수 호출 오버 헤드 (이미 소음 일뿐입니다)가 없는 것보다 훨씬 유익하고 효과적 입니다.


또한 하드웨어에서 실제로 실행되기 전에 ASM에 대한 최적화를 수행 할 수 있다고 생각합니다.

이것이 마음에들 때마다 컴파일러에서 일하는 똑똑한 사람들이 수십 년 동안 기계 코드를 생성하는 것보다 GCC와 같은 도구를 훨씬 더 잘 만들고 있다는 것을 기억합니다. 어떤 종류의 마이크로 컨트롤러 관련 작업을 수행하지 않는 한 걱정하지 않아도 좋습니다.

코드에 점점 더 많은 함수와 더 많은 객체와 클래스를 추가하면 더 작은 코드 조각 사이에 점점 더 많은 매개 변수가 전달된다고 가정합니다.

최적화 할 때 시간 낭비라고 가정하면 코드 성능에 대한 사실이 필요합니다. 특수 도구를 사용하여 대부분의 시간을 프로그램에서 사용하는 곳을 찾아서 최적화하고 반복하십시오.


요약하면; 컴파일러가 작업을 수행하고 알고리즘 및 데이터 구조 개선과 같은 중요한 일에 집중하십시오. 귀하의 질문에 언급 한 모든 패턴은 그것을 돕기 위해 존재합니다.

추신 :이 두 Crockford의 대화가 제 머리에 터져서 다소 관련이 있다고 생각합니다. 첫 번째는 매우 간단한 CS 역사입니다 (정확한 과학으로 항상 알고있는 것이 좋습니다). 두 번째는 왜 우리가 좋은 것을 거부하는지에 관한 것입니다.


나는이 답변이 가장 마음에 든다. 인간은 컴파일러를 두 번 추측하고 병목 현상이 발생한 위치에서 촬영하는 것이 끔찍합니다. 물론 큰 O 시간 복잡성은 알아야 할 것이지만 큰 100 줄 스파게티 방법 대 팩토리 메서드 호출 + 일부 가상 메서드 디스 패칭은 결코 토론해서는 안됩니다. 이 경우 성능이 전혀 흥미롭지 않습니다. 또한 어려운 사실과 측정없이 "최적화"한다는 것은 시간 낭비입니다.
sara

4

나는 당신이 식별하는 트렌드가 소프트웨어 개발에 대한 진실을 지적한다고 믿는다. 프로그래머 시간은 CPU 시간보다 비싸다. 지금까지 컴퓨터는 더 빠르고 저렴 해졌지만 엉킨 응용 프로그램의 혼란은 수천 시간이 아니라면 수백 시간이 걸릴 수 있습니다. 급여, 복리 후생, 사무 공간 등의 비용을 감안할 때, 조금 느리게 실행될 수 있지만 더 빠르고 안전하게 변경할 수있는 코드를 갖는 것이 더 비용 효율적입니다.


1
동의하지만 모바일 장치가 인기를 얻고있어 큰 예외라고 생각합니다. 처리 능력이 향상되고 있지만 iPhone 앱을 만들 수 없으며 웹 서버에서와 같이 메모리를 추가 할 수있을 것으로 기대합니다.
JeffO

3
@JeffO : 동의하지 않습니다. 쿼드 코어 프로세서가 장착 된 모바일 장치는 이제 정상적이며 성능 (특히 배터리 수명에 영향을 미침)은 안정성보다 중요하지 않습니다. 휴대 전화 나 태블릿의 속도가 느리면 리뷰가 열악하고 불안정한 것이 도축됩니다. 모바일 앱은 매우 역동적이며 거의 매일 바뀌고 있습니다. 소스는 계속 유지되어야합니다.
mattnz

1
@JeffO : 가치있는 것은 안드로이드에서 사용되는 가상 머신이 매우 나쁘다는 것입니다. 벤치 마크에 따르면 네이티브 코드보다 수십 배 느릴 수 있습니다 (최상의 품종은 일반적으로 조금 느립니다). 아무도 신경 쓰지 않아요 응용 프로그램을 작성하는 것이 빠르며 CPU가 거기에 앉아 엄지 손가락을 돌리고 사용자 입력의 90 %를 기다리고 있습니다.
Jan Hudec

원시 CPU 벤치 마크보다 성능이 뛰어납니다. AV가 업데이트를 스캔하고 내가 좋아하는 것보다 오래 멈추는 경우와 쿼드 코어 2Gb RAM 모델을 제외하고 내 안드로이드 폰은 정상적으로 작동합니다! 오늘날 대역폭 (네트워크 또는 메모리)이 주요 병목 현상 일 수 있습니다. 초고속 CPU가 99 %의 시간을 낭비하고 있으며 전체적인 경험이 여전히 좋지 않습니다.
gbjbaanb

4

20 년 이상 전에, "오래되거나 나쁘지 않은"새로운 전화를하지 않는 것으로 추측되는 규칙은 인쇄 된 페이지에 맞게 기능을 충분히 작게 유지하는 것이 었습니다. 우리는 도트 ​​매트릭스 프린터를 가지고 있었으므로 줄 수는 일반적으로 페이지 당 줄 수에 대해 한두 가지 선택으로 고정되었습니다.

문제, 유지 보수성, 성능, 테스트 가능성, 가독성의 여러 측면을 요구하고 있습니다. 성능에 더 많이 의존할수록 코드의 유지 관리 및 판독성이 떨어 지므로 각 프로그래머마다 변할 수있는 안락함을 찾아야합니다.

컴파일러에서 생성 한 코드 (기계 코드 인 경우)는 함수가 클수록 레지스터의 중간 값을 스택에 쏟을 필요가 있습니다. 스택 프레임을 사용하면 스택 소비가 더 커집니다. 함수가 작을수록 데이터가 레지스터에 더 많이 머무를 수 있고 스택에 대한 의존도가 줄어 듭니다. 기능 당 더 작은 스택 덩어리가 자연스럽게 필요했습니다. 스택 프레임에는 성능에 대한 장단점이 있습니다. 더 작은 기능은 더 많은 기능 설정 및 정리를 의미합니다. 물론 컴파일 방법, 컴파일러에 제공하는 기회에 따라 다릅니다. 하나의 2500 라인 함수 대신 250 10 라인 함수가있을 수 있습니다. 컴파일러는 전체적으로 최적화 할 수 있거나 선택할 수 있다면 컴파일러가 가져올 2500 라인 함수입니다. 그러나 250 개의 10 줄 함수를 가져 와서 2, 3, 4, 250 개의 개별 파일로 분산시키고 각 파일을 개별적으로 컴파일하면 컴파일러는 거의 가능한 죽은 코드를 최적화 할 수 없습니다. 결론은 여기에 장단점이 있으며 이것에 대한 일반적인 규칙을 정하는 것은 불가능하거나 이것이 최선의 방법입니다.

사람이 화면이나 페이지에서 합리적인 글꼴로 볼 수있는 합리적인 크기의 기능은 상당히 큰 코드보다 더 잘 이해하고 이해할 수있는 것입니다. 그러나 다른 많은 작은 함수를 호출하는 다른 많은 작은 함수를 호출하는 작은 함수 인 경우 해당 코드를 이해하기 위해 여러 개의 창이나 브라우저가 필요하므로 가독성 측면에서 아무것도 사지 않았습니다.

유닉스 방식은 세련되고 세련된 레고 블록이라는 용어를 사용하는 것입니다. 테이프 사용을 중단 한 후 몇 년 동안 테이프 기능을 사용하는 이유는 무엇입니까? Blob이 잘 작동하고 후면에서 테이프 인터페이스를 파일 인터페이스로 교체하고 프로그램의 장점을 활용할 수 있습니다. scsi가 우세한 인터페이스를 ide로 교체 한 후 (이후에 다시 돌아올 때) cdrom 굽기 소프트웨어를 다시 작성하는 이유 다시 연마 된 서브 블록을 발전시키고 한쪽 끝을 새로운 인터페이스 블록으로 교체하십시오 (또한 하드웨어 설계자가 하드웨어 설계에서 단순히 인터페이스 블록을 고정하여 일부 경우 scsi 드라이브가 scsi 인터페이스를 선호 함을 이해합니다). , 각각 잘 정의 된 목적과 잘 정의 된 입력 및 출력으로 합리적인 크기의 광택이있는 레고 ​​블록을 제작하십시오. 레고 블록을 중심으로 테스트를 래핑 한 다음 동일한 블록을 사용하고 동일한 블록과 블록을 중심으로 사용자 인터페이스 및 운영 체제 인터페이스를 래핑 할 수 있습니다. 각 끝에. 모든 블록 인터페이스가 잘 설계되고 기능이 잘 이해되는 한 최소한의 접착제로도 많은 것을 만들 수 있습니다. 알려진 크기와 모양의 파란색과 빨간색과 검은 색과 노란색의 레고 블록과 마찬가지로 많은 것을 만들 수 있습니다. 모든 블록 인터페이스가 잘 설계되고 기능이 잘 이해되는 한 최소한의 접착제로도 많은 것을 만들 수 있습니다. 알려진 크기와 모양의 파란색과 빨간색과 검은 색과 노란색의 레고 블록과 마찬가지로 많은 것을 만들 수 있습니다. 모든 블록 인터페이스가 잘 설계되고 기능이 잘 이해되는 한 최소한의 접착제로도 많은 것을 만들 수 있습니다. 알려진 크기와 모양의 파란색과 빨간색과 검은 색과 노란색의 레고 블록과 마찬가지로 많은 것을 만들 수 있습니다.

모든 개인은 다르며, 세련되고 잘 정의되고 테스트되고 읽을 수있는 정의는 다양합니다. 예를 들어 교수가 프로그래밍 규칙을 지시하는 것은 비전문가가 아니기 때문에 전문가로서 나쁘지 않을 수도 있지만 교수 또는 대학원 학생 조교에서 코드를 쉽게 읽고 채점하는 작업을하는 경우도 있습니다. ... 전문적으로도 각 직업마다 여러 가지 이유로 다른 규칙이있을 수 있습니다. 일반적으로 권력을 가진 한 명 또는 소수의 사람들이 옳고 그름에 대해 자신의 의견을 가지고 있으며 그 힘으로 자신이하는 일을 지시 할 수 있습니다. 거기에서 (또는 끊거나 해고되거나 어떻게 든 권력을 얻습니다). 이러한 규칙은 가독성, 성능, 테스트 가능성, 이식성에 대한 일종의 사실을 기반으로하기 때문에 종종 의견에 기반합니다.


“따라서 각 프로그래머마다 변할 수있는 안락함을 찾아야합니다.”최적화 수준은 각 프로그래머가 좋아하는 것이 아니라 각 코드의 성능 요구 사항에 따라 결정되어야한다고 생각합니다.
svick

프로그래머가 컴파일러에게 일반적으로 컴파일러를 최적화하지 않도록 컴파일러에 최적화하도록 명령했다고 가정하면 컴파일러는 명령 줄에서 IDE가 사용되는 경우 다른 기본값을 가질 수 있습니다. 그러나 프로그래머는 함수의 크기를 최적화 할만큼 충분히 알지 못하고 어디에서 쓸데없는 목표를 가지고 있습니까? 핸드 튜닝 성능은 가독성에 부정적인 영향을 미치는 경향이 있으며, 특히 유지 관리 가능성은 테스트 가능성이 어느 쪽이든 될 수 있습니다.
old_timer

2

컴파일러가 얼마나 똑똑한가에 달려 있습니다. 일반적으로 옵티 마이저를 능가하려는 시도는 나쁜 생각이며 실제로 컴파일러에게 최적화 기회를 빼앗길 수 있습니다. 우선, 당신은 아마 그것이 무엇을 할 수 있는지에 대한 단서가 없을 것입니다. 그리고 당신이 실제로하는 일의 대부분은 그것이 얼마나 잘 수행하는지에 영향을줍니다.

조기 최적화는 프로그래머가 그렇게하려고 시도하고 실제로 수행하려는 중요한 경로에 있지 않은 코드를 유지하기가 어렵다는 개념입니다. 대부분의 시간에 앱이 실제로 IO 이벤트를 기다리는 동안 차단 될 때 가능한 한 많은 CPU를 짜내려고 시도하는 것이 예를 들어 많이 볼 수 있습니다.

가장 좋은 방법은 정확성을 위해 코딩하고 프로파일 러를 사용하여 실제 성능 병목 현상을 찾아 내고 중요한 경로에 무엇이 있는지, 개선 할 수 있는지 여부를 분석하여 문제를 해결하는 것입니다. 종종 몇 가지 간단한 수정이 먼 길을갑니다.


0

[컴퓨터 시간 요소]

Looser 커플 링 및 더 작은 기능에 대한 리팩토링이 코드 속도에 영향을 줍니까?

그렇습니다. 그러나이 "심 / 결선"코드를 제거하는 것은 통역사, 컴파일러 및 JIT 컴파일러의 몫이며 일부는 다른 것보다 더 잘 수행하지만 일부는 그렇지 않습니다.

다중 파일 문제는 I / O 오버 헤드를 증가시켜 컴퓨터 시간에 상당한 속도를 좌우합니다.

[인간 속도 요소]

(그리고 관심을 가져야합니까?)

아니 당신은 상관하지 않아야합니다. 요즘 컴퓨터와 회로는 훨씬 빠르며 네트워크 대기 시간, 데이터베이스 I / O 및 캐싱과 같은 다른 요소가 대신합니다.

따라서 네이티브 코드 실행 자체에서 2x-4x 속도가 느려지면 종종 다른 요인에 의해 익사합니다.

다중 파일로드에 이르기까지 다양한 캐싱 솔루션이이를 관리합니다. 항목을로드하고 처음으로 병합하는 데 시간이 더 걸릴 수 있지만 다음에 정적 파일의 경우 캐싱은 단일 파일이로드되는 것처럼 작동합니다. 캐싱은 다중 파일로드에 대한 솔루션으로 제공됩니다.


0

답변 (당신이 그것을 놓친 경우)

그렇습니다. 성능에 신경 쓰지 말고 코드 작성 방법에주의하십시오.

한마디로

성능에 신경 쓰지 마십시오

문제의 맥락에서 똑똑한 컴파일러와 통역사는 이미 그것을 처리합니다.

유지 관리 가능한 코드 작성에주의

유지 보수 비용이 합리적인 인간 이해 수준에있는 코드. 즉, 각각의 코드를 이해하더라도 이해하기 어려운 코드를 만드는 1000 개의 작은 함수를 작성하지 말고 이해하기에는 너무 큰 1 개의 신 객체 함수를 작성하지 말고 사람에게 이해가 잘되는 10 개의 잘 설계된 함수를 작성하십시오. 유지 관리가 용이합니다.

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