왜 우리는 속도를 위해 추상화를 교환해야합니까?


11

고급 언어가 속도 측면에서 하위 언어에 도달하지 못하는 이유는 무엇입니까? 고급 언어의 예로는 Python, Haskell 및 Java가 있습니다. 저수준 언어는 정의하기가 까다로울 수 있지만 C라고 가정 해 봅시다. 인터넷 전체에서 비교를 찾을 수 있으며 은 모두 C가 훨씬 빠르며 때로는 10 배 이상이라는 데 동의합니다.1

이러한 성능 차이가 큰 이유는 무엇이며 고급 언어를 따라 잡을 수없는 이유는 무엇입니까?

처음에는 이것이 모든 컴파일러의 결함이며 향후 개선 될 것이라고 믿었지만 가장 인기있는 고급 언어 중 일부는 수십 년 동안 사용되어 왔으며 속도면에서 여전히 뒤쳐져 있습니다. 단순히 C 구문 트리와 유사한 것으로 컴파일 한 다음 기계 코드를 생성하는 동일한 절차를 수행 할 수 없습니까? 아니면 구문 자체와 관련이 있습니까?


1 예 :


5
"그리고 그들은 모두 C가 훨씬 빠르다는 데 동의합니다."-확실히 틀 렸습니다.
Raphael

2
어쨌든, 포스트는 비슷한 생각을 가진 질문에 대한 나의 대답의해 가장 잘 대답 된다고 생각합니다 . 복제?
Raphael

2
여기여기도 참조 하십시오 . 정크 답변을 조심하십시오.
Raphael

관련성 : stackoverflow.com/questions/6964392/… 모든 "고급 언어"가 느리다는 신화는 매우 슬프다.
xji

나는 추상화! = 느림에 대해 다른 사람들에게 동의하지만 컴퓨터 과학 교사 (나는 하나였다)가 알지 못하는 훨씬 더 큰 문제가 있음을 두려워한다. 즉, 실제 프로그램 (1000 줄 이상의 코드)에는 여러 가지 방법이 있으며 그 순서에 따라 성능이 다를 수 있습니다. big-O에 대한 생각만으로는 요점을 놓치게됩니다. 여기를 확인 하십시오 .
Mike Dunlavey

답변:


19

일부 신화를 폭로

  1. 빠른 언어와 같은 것은 없습니다. 일반적으로 언어는 빠른 코드를 생성 할 수 있지만 다른 언어는 다른 벤치 마크에서 우수합니다. 우리는 결함이있는 특정 벤치 마크에서 언어의 순위를 정할 수 있지만, 언어를 빈틈없이 평가할 수는 없습니다.

  2. C 코드는 모든 성능을 필요로하는 사람들이 C를 사용하기 때문에 더 빠른 경향이 있습니다. C가 "10 배 더 빠름"으로 빠르다는 통계는 정확하지 않을 수 있습니다. 왜냐하면 파이썬을 사용하는 사람들은 그다지 신경 쓰지 않기 때문입니다. 속도에 관한 것이며 최적의 파이썬 코드를 작성하지 않았습니다. 우리는 이것을 Haskell과 같은 언어에서 특히 봅니다. 정말로 열심히 노력한다면 C와 동등한 성능을 가진 Haskell을 작성할 수 있습니다. 그러나 대부분의 사람들은 그 성능이 필요하지 않으므로 많은 비교가 이루어지지 않습니다.

  3. 때로는 추상화가 아니라 안전하지 않아 C를 빠르게 만듭니다. 어레이 바운드 및 널 포인터 검사가 없기 때문에 시간이 절약되며 수년 동안 수많은 보안 허점이 발생했습니다.

  4. 언어가 빠르지 않고 구현이 빠릅니다. 속도가 목표가 아니기 때문에 많은 추상 언어가 느리게 시작되지만 점점 더 많은 최적화가 추가되면 더 빨라집니다.

추상화 대 속도 트레이드 오프가 정확하지 않을 수 있습니다. 더 나은 비교를 제안합니다.

단순성, 속도, 추상화 : 두 가지를 선택하십시오.

다른 언어로 동일한 알고리즘을 실행하는 경우 속도 문제는 "이 작업을 수행하기 위해 런타임에 얼마나 많은 작업을 수행해야합니까?"라는 문제로 귀착됩니다.

매우 추상적 인 언어로 간단하게 우리가 런타임까지 데이터의 표현에 대해 알고하지 않기 때문에, 파이썬이나 자바 스크립트로, 포인터의 것을 많이가 결국 드 참조하고 느린 실행시에 발생하는 동적 검사,.

마찬가지로 컴퓨터를 손상시키지 않기 위해 수행해야 할 검사가 많이 있습니다. 파이썬에서 함수를 호출하면 호출하는 객체가 실제로 함수인지 확인해야합니다. 그렇지 않으면 끔찍한 일을하는 임의의 코드가 실행될 수 있습니다.

마지막으로 대부분의 추상 언어는 가비지 수집으로 인한 오버 헤드가 있습니다. 대부분의 프로그래머는 동적으로 할당 된 메모리의 수명을 추적해야한다는 것은 고통스럽고 가비지 수집기가 런타임에이를 수행하도록하는 데 동의했습니다. C 프로그램이 GC에 소비하지 않아도되기까지 시간이 걸립니다.

초록은 느린 것을 의미하지 않습니다

그러나 추상적이고 빠른 언어가 있습니다. 이 시대에 가장 지배적 인 것은 녹입니다. 차용 검사기 및 정교한 유형 시스템을 도입하여 추상 코드를 허용하고 컴파일 타임 정보를 사용하여 런타임시 수행해야하는 작업량 (가비지 수집)을 줄입니다.

정적으로 유형이 지정된 언어는 런타임 검사 수를 줄여 시간을 절약하고 컴파일 타임에 형식 검사기를 기쁘게 요구하여 복잡성을 유발합니다. 마찬가지로, 타입 시스템에 값이 널 (null)이 될 수 있는지 여부를 인코딩하는 언어가 있으면 컴파일 시간 널 포인터 검사로 시간을 절약 할 수 있습니다.


2
"모든 수준의 성능이 필요한 사람들이 C를 사용하기 때문에 C 코드가 더 빠른 경향이 있습니다." "X 년 Y / Z 경험을 가진 X 년 학생 / 전문가가 작성한 평균 코드 실행 시간"형식의 벤치 마크를보고 싶습니다. C에 대한 답은 일반적으로 작은 X 및 Y에 대해 "코드가 정확하지 않습니다"라고 기대합니다. 성능 C 약속 의 잠재력 을 활용하는 데 얼마나 많은 경험 / 전문 지식이 필요한지 보는 것이 정말 흥미로울 것 입니다.
Raphael

하스켈은 실제로 규칙을 증명하는 예외입니다. ;) C ++은 공유 포인터를 중첩하지 않고 C만큼 빠르기 만한다면 스마트 포인터로 GC에 대해 어느 정도 합리적인 중간 근거를 찾았다 고 생각합니다.
Kaveh

0

여기에 몇 가지 주요 아이디어가 있습니다.

  • wrt 추상화 대 속도를 만드는 쉬운 비교 / 사례 연구는 java 대 c ++입니다. java는 메모리 관리와 같은 c ++의 하위 레벨 측면을 추상화하도록 설계되었습니다. 초기에 (1990 년대 중반 언어의 발명 전후) 자바 가비지 탐지는 그리 빠르지는 않았지만, 수십 년에 걸친 연구 끝에 가비지 수집기는 극도로 미세 조정 / 빠른 / 최적화되어 가비지 수집기가 크게 제거되었습니다. 자바 성능 저하. 예를 들어이 1998 헤드 라인 : 성능 테스트에서 Java를 C ++ / javaworld 만큼 빠르게 보여줍니다

  • 프로그래밍 언어와 그 긴 진화는 일종의 초월 디자인 패턴으로서 고유 한 "피라미드 / 계층 구조"를 가지고 있습니다. 피라미드의 맨 위에는 피라미드의 다른 하위 섹션을 제어하는 ​​것이 있습니다. 즉, 빌딩 블록은 빌딩 블록으로 구성됩니다. 이것은 API 구조에서도 볼 수 있습니다. 이런 의미에서, 더 큰 추상화는 항상 다른 구성 요소를 제어하는 ​​피라미드의 상단에 새로운 구성 요소를 가져옵니다. 어떤 의미에서는 모든 언어가 서로 같은 수준에 있지는 않지만 언어는 다른 언어의 루틴을 호출합니다. 예를 들어, 많은 스크립팅 언어 (python / ruby)는 종종 C 또는 C ++ 라이브러리를 호출합니다. 숫자 또는 행렬 루틴이 대표적인 예입니다. 더 높은 수준의 언어와 낮은 수준의 언어가 있으며 높은 수준의 언어는 말하기 위해 낮은 수준의 언어를 호출합니다. 이런 의미에서 상대 속도를 측정하는 것은 실제로 비교할 수 없습니다.

  • 추상화 / 속도 트레이드 오프, 즉 주요 설계 목표를 최적화하기 위해 항상 새로운 언어가 개발되고 있다고 말할 수도 있습니다. 어쩌면 더 큰 추상화가 항상 속도를 희생 시키지는 않지만 새로운 디자인에서는 항상 더 나은 균형을 찾고 있습니다. 예를 들어 Google Go는 트레이드 오프를 염두에두고 여러 가지면에서 특별히 최적화되었으며 동시에 높은 수준과 성능을 모두 갖추 었습니다. 예 : Google Go : 엔터프라이즈 / 기술 분야 에서 Google의 프로그래밍 언어가 Java와 경쟁 할 수있는 이유


0

내가 성능에 대해 생각하는 방식은 "고무가 길을 만나는 곳"입니다. 컴퓨터는 추상화가 아닌 명령어를 실행합니다.

내가보고 싶은 것은 이것입니다. 실질적으로 최종 결과에 기여하여 "계속 유지"되는 모든 명령입니까? 너무 간단한 예로, 1024 개 항목 표에서 항목을 찾아보십시오. 프로그램이 답을 알기 전에 10 비트를 "학습"해야하기 때문에 이는 10 비트 문제입니다. 알고리즘이 이진 검색 인 경우 모든 반복은 불확실성을 2 배로 축소하기 때문에 1 비트의 정보를 제공합니다. 따라서 각 비트 당 하나씩 10 회 반복이 수행됩니다.

반면에 선형 탐색은 첫 번째 반복이 불확실성을 매우 작은 요소로 축소하기 때문에 처음에는 매우 비효율적입니다. 그래서 그들은 노력한 노력에 대해 많이 배우지 않습니다.

그래, 만약 컴파일러가 사용자가 "추상적 인"것으로 간주되는 방식으로 좋은 명령어를 랩핑 할 수 있다면 괜찮습니다.


0

본질적으로 추상화는 프로그래머와 시스템의 하위 계층 (컴파일러, 라이브러리 및 런타임 시스템) 모두에 대한 정보 통신을 줄입니다. 추상화를 위해, 이것은 일반적으로 하위 계층이 프로그래머가 지정되지 않은 동작과 관련이 없다고 가정 할 수있게하여 지정된 동작을 제공하는 데 더 큰 유연성 을 제공합니다.

이 "무정의"측면에서 얻을 수있는 잠재적 이점의 예는 데이터 레이아웃입니다. C (낮은 추상화)에서 컴파일러는 데이터 레이아웃 최적화에 더 제한적입니다. 컴파일러가 (예를 들어, 프로파일 정보를 통해) 핫 / 콜드 또는 허위 공유 방지 최적화가 유리할 것임을 식별 할 수 있더라도, 일반적으로 그러한 적용이 금지된다. ( "as as"를 지정하는 것은 자유로울 수 있습니다. 즉, 사양을보다 추상적으로 취급하지만 모든 잠재적 부작용을 도출하면 컴파일러에 부담이됩니다.

보다 추상적 인 사양은 또한 트레이드 오프와 사용의 변화에 ​​대해 더욱 강력합니다. 하위 시스템은 새로운 시스템 특성 또는 새로운 용도를 위해 프로그램을 재 최적화하는 데 제약이 적습니다. 보다 구체적인 사양은 프로그래머가 다시 작성하거나 하위 계층에서 "있는 것처럼"동작을 보장하기 위해 추가 노력을 기울여야합니다.

정보 숨기기 추상화의 성능을 저해하는 측면은 "표현할 수 없음"이며, 하위 계층은 일반적으로 "모름"으로 처리합니다. 이는 하위 계층이 일반적인 일반 용도, 대상 용도 또는 특정 프로파일 정보와 같은 다른 수단과의 최적화에 유용한 정보를 식별해야 함을 의미합니다.

정보 숨기기의 영향은 다른 방향에서도 작동합니다. 프로그래머는 모든 세부 사항을 고려하고 지정하지 않아도 생산성을 높일 수 있지만 프로그래머는 높은 수준의 설계 선택의 영향에 대한 정보가 적을 수 있습니다.

다른 한편으로, 코드가 더 구체적 일 때 (추상적이지 않은 경우), 시스템의 하위 계층은 지시를 받았을 때 지시받은 것을 더 간단하게 수행 할 수 있습니다. 코드가 대상 용도로 잘 작성되면 대상 용도에 잘 맞습니다. 덜 추상적 인 언어 (또는 프로그래밍 패러다임)는 프로그래머 가 세부 설계 및 주어진 언어로 쉽게 하위 계층에 전달할 수없는 정보를 사용하여 구현을 최적화 할 수 있도록 합니다 .

언급 된 바와 같이, 추가적인 프로그래머 기술 및 노력이 가치있는 결과를 생성 할 수있을 때 덜 추상적 인 언어 (또는 프로그래밍 기술)가 매력적이다. 더 많은 프로그래머 노력과 기술이 적용되면 결과는 일반적으로 더 좋습니다. 또한 성능에 중요한 응용 프로그램에 덜 사용되는 언어 시스템 (개발 노력이나 안정성을 강조하는 대신 경계 검사 및 가비지 수집은 프로그래머의 생산성뿐만 아니라 정확성에 관한 것입니다. 추상화는 프로그래머의 정신 부하를 줄여 신뢰성을 향상시킬 수 있습니다) 성능 향상에 대한 압력이 줄어 듭니다.

최적화는 일반적으로 특정 용도에 맞게 코드를 조정하여 최적화 할 수 있기 때문에 반복하지 마십시오. 이것은 명백한 신뢰성과 프로그래밍 노력에 영향을 미칩니다.

언어에 의해 제공되는 추상화는 또한 덜 무거운 추상화를 선택할 수단이없는 바람직하지 않거나 불필요한 작업을 포함 할 수 있습니다. 하위 계층에서 불필요한 작업을 발견하고 제거 할 수있는 경우도 있지만 (예 : 경계 검사가 루프 본문에서 추출되어 일부 경우에는 완전히 제거 될 수 있음),이를 위해 유효한 최적화를 결정하려면 더 많은 "기술과 노력"이 필요합니다. 컴파일러

언어 연령과 인기도 숙련 된 프로그래머의 가용성과 시스템의 하위 계층 품질 (성숙한 라이브러리 및 코드 예제 포함) 모두에서 중요한 요소입니다.

이러한 비교에서 또 다른 혼란 요인은 사전 컴파일과 적시 컴파일 간의 다소 직교적인 차이입니다. JIT (Just-In-Time) 컴파일은 프로파일 정보 (프로그래머에 의존하지 않고 프로파일 실행을 제공하지 않음) 및 시스템 별 최적화 (시간 단위 컴파일이 광범위한 호환성을 목표로 할 수 있음)를보다 쉽게 ​​이용할 수 있지만 공격적인 최적화의 오버 헤드는 다음과 같이 설명됩니다. 런타임 성능의 일부. JIT 결과를 캐싱하여 일반적으로 사용되는 코드의 오버 헤드를 줄입니다. (이진 재 최적화의 대안은 JIT 컴파일의 몇 가지 장점을 제공 할 수 있지만, 기존의 이진 배포 형식은 대부분의 소스 코드 정보를 삭제하여 시스템이 특정 구현에서 의도를 식별하도록합니다.)

(프로그래머 제어에 중점을두기 때문에 추상화 언어가 낮을수록 사전 컴파일 사용을 선호합니다. 링크 타임 구현 선택은 더 큰 프로그래머 제어를 제공하지만 설치 시간 컴파일은 허용 될 수 있습니다. JIT 컴파일은 중요한 제어를 희생시킵니다. )

벤치마킹 방법론의 문제도 있습니다. 동등한 노력 / 기술은 확립하기가 사실상 불가능하지만, 언어 목표가 결과를 편향시킬 수도 있습니다. 낮은 최대 프로그래밍 시간이 필요한 경우, 더 추상적 인 언어의 간단한 관용적 표현에 비해 덜 추상적 인 언어의 프로그램을 완전히 작성하지 못할 수도 있습니다. 높은 최대 프로그래밍 시간 / 노력이 허용 된 경우, 저 추상 언어가 유리할 것입니다. 최선의 노력의 결과를 나타내는 벤치 마크는 자연스럽지 않은 언어에 유리하게 편향 될 수 있습니다.

다른 프로그래밍 패러다임의 장점을 얻기 위해 언어로 덜 관용적 인 방식으로 프로그래밍하는 것이 때때로 가능하지만, 표현력이 이용 가능한 경우에도 그러한 표현을위한 트레이드 오프는 바람직하지 않을 수 있습니다.

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