프로그램이 두 개의 다른 언어로 작성되었다고 가정하십시오. 컴파일러가 동일한 바이트 코드를 생성하는 경우 언어 Y 대신 언어 X를 사용해야하는 이유는 무엇입니까? 한 언어가 다른 언어보다 빠르다는 것은 무엇입니까?
"C는 가장 빠른 언어이고 ATS는 C와 같은 언어입니다." 프로그래밍 언어에 대한 "빠른"정의를 이해하려고했습니다.
프로그램이 두 개의 다른 언어로 작성되었다고 가정하십시오. 컴파일러가 동일한 바이트 코드를 생성하는 경우 언어 Y 대신 언어 X를 사용해야하는 이유는 무엇입니까? 한 언어가 다른 언어보다 빠르다는 것은 무엇입니까?
"C는 가장 빠른 언어이고 ATS는 C와 같은 언어입니다." 프로그래밍 언어에 대한 "빠른"정의를 이해하려고했습니다.
답변:
언어 Y보다 언어 X를 선택하는 데는 여러 가지 이유가있을 수 있습니다. 프로그램 가독성, 프로그래밍 용이성, 많은 플랫폼으로의 이식성, 우수한 프로그래밍 환경의 존재가 그러한 이유 일 수 있습니다. 그러나 질문에서 요청한대로 실행 속도 만 고려하겠습니다. 문제는 예를 들어 개발 속도를 고려하지 않는 것 같습니다.
두 언어가 동일한 바이트 코드로 컴파일 할 수 있지만 동일한 코드가 생성되는 것은 아닙니다.
실제로 바이트 코드는 특정 가상 머신에 대한 코드 일뿐입니다. 엔지니어링 이점이 있지만 특정 하드웨어에 대해 직접 컴파일 할 때 근본적인 차이점이 없습니다. 따라서 동일한 머신에서 직접 실행되도록 컴파일 된 두 언어를 비교하는 것도 고려할 수 있습니다.
이것은 언어의 상대 속도 문제는 첫 번째 컴파일러로 거슬러 올라가는 오래된 것입니다.
수년 동안, 그 초기에는 전문가가 직접 작성한 코드가 컴파일 된 코드보다 빠르다고 생각했습니다. 즉, 기계 언어는 Cobol 또는 Fortran과 같은 고급 언어보다 빠른 것으로 간주되었습니다. 그리고 그것은 더 빠르고 보통 더 작았습니다. 고급 언어는 컴퓨터 과학자가 아닌 많은 사람들이 사용하기가 훨씬 쉽기 때문에 여전히 개발되었습니다. 고급 언어를 사용하는 비용에도 확장 비율이라는 이름이 있었는데, 이는 생성 된 코드의 크기 (그 당시 매우 중요한 문제) 또는 실제로 실행 된 명령의 수와 관련 될 수 있습니다. 이 개념은 주로 실험적이지만 컴파일러가 오늘날 표준에 의해 상당히 간단한 작업을 수행했기 때문에 처음에는 비율이 1보다 컸습니다.
따라서 기계어는 Fortran보다 더 빠릅니다.
물론, 컴파일러가 더 정교 해짐에 따라 어셈블리 언어로 프로그래밍하는 것이 이제는 매우 드물다는 점에서 수년에 걸쳐 바뀌 었습니다. 대부분의 응용 프로그램에서 어셈블리 언어 프로그램은 컴파일러 최적화로 생성 된 코드와 경쟁이 치열합니다.
이것은 고려되는 언어에 사용할 수있는 컴파일러의 품질, 소스 코드를 분석하고 그에 따라 최적화하는 능력이라는 주요 문제가 있음을 보여줍니다.
이 기능은 컴파일러의 작업을보다 쉽게하기 위해 소스의 구조적 및 수학적 속성을 강조하기 위해 언어의 특징에 따라 일부 확장 될 수 있습니다. 예를 들어, 언어는 컴파일러가 최적화를 위해 이러한 속성을 사용할 수 있도록 사용자 정의 함수의 대수 속성에 대한 설명을 포함 할 수 있습니다.
언어의 프로그래밍 패러다임이 실제 머신이든 가상 머신이든 코드를 해석하는 머신의 기능에 더 가까울 때 컴파일 프로세스가 더 쉬워 지므로 더 나은 코드를 생성 할 수 있습니다.
또 다른 요점은 언어로 구현 된 패러다임이 프로그래밍되는 문제 유형에 따라 폐쇄되는지 여부입니다. 특정 프로그래밍 패러다임에 특화된 프로그래밍 언어는 해당 패러다임과 관련된 기능을 매우 효율적으로 컴파일 할 것으로 예상됩니다. 따라서, 프로그래밍 언어의 선택은 명확성 및 속도를 위해 프로그래밍되는 문제의 종류에 적합한 프로그래밍 언어의 선택에 의존 할 수있다.
시스템 프로그래밍에 대한 C의 인기는 아마도 C가 기계 아키텍처에 가깝고 시스템 프로그래밍도 해당 아키텍처와 직접 관련되어 있기 때문일 것입니다.
다른 프로그래밍 문제는 로직 프로그래밍 및 제약 조건 해결 언어를 사용한 빠른 실행으로보다 쉽게 프로그래밍 됩니다 .
복잡한 반응 시스템 은 Esterel 과 같은 특수 동기 프로그래밍 언어를 사용하여 매우 효율적으로 프로그래밍 할 수 있으며, 이러한 시스템에 대한 매우 전문적인 지식을 구현하고 매우 빠른 코드를 생성합니다.
또는 극단적 인 예를 들기 위해 파서를 프로그래밍하는 데 사용되는 구문 설명 언어와 같은 일부 언어는 고도로 전문화되어 있습니다. 파서 생성기는 아무것도하지만, 같은 언어를위한 컴파일러입니다. 물론 튜링이 완전하지는 않지만,이 컴파일러는 효율적인 파싱 프로그램 생성과 같은 전문 분야에 매우 적합합니다. 지식의 영역이 제한되어 최적화 기술을 매우 전문화하고 미세 조정할 수 있습니다. 이러한 파서 생성기는 일반적으로 다른 언어로 코드를 작성하여 얻을 수있는 것보다 훨씬 낫습니다. 제한된 클래스의 문제에 대해 우수하고 빠른 코드를 생성하는 컴파일러를 갖춘 고도로 전문화 된 언어가 많이 있습니다.
따라서 큰 시스템을 작성할 때 단일 언어에 의존하지 않고 시스템의 다른 구성 요소에 가장 적합한 언어를 선택하는 것이 좋습니다. 물론 이것은 호환성 문제를 일으킨다.
종종 중요한 또 다른 요점은 프로그래밍되는 주제에 대한 효율적인 라이브러리의 존재입니다.
마지막으로 속도는 유일한 기준이 아니며 코드 안전 (예 : 잘못된 입력 또는 시스템 오류에 대한 복원력), 메모리 사용, 프로그래밍 용이성 (패러다임 호환성이 실제로 도움이 될 수 있음)과 같은 다른 기준과 충돌 할 수 있습니다. ), 객체 코드 크기, 프로그램 유지 보수성 등
속도가 항상 가장 중요한 매개 변수는 아닙니다. 또한 평균 복잡도이거나 더 복잡한 대소 문자 복잡도 일 수있는 복잡성과 같이 다른 모양을 취할 수도 있습니다. 또한 작은 프로그램처럼 큰 시스템에는 속도가 중요한 부분이 있고 다른 부분은 그다지 중요하지 않은 부분이 있습니다. 미리 결정하기가 항상 쉬운 것은 아닙니다.
모든 것이 결국 CPU * 에서 실행되지만 언어마다 차이가 있습니다. 여기 몇 가지 예가 있어요.
해석 언어 일부 언어가되어 해석 보다는 컴파일 예를 파이썬, 루비와 matlab에 들어. 즉, Python 및 Ruby 코드는 기계 코드로 컴파일되지 않고 즉석에서 해석됩니다. Python과 Ruby를 가상 머신으로 컴파일 할 수 있습니다 (다음 요점 참조). 이 질문 도 참조하십시오 . 일반적으로 해석은 여러 가지 이유로 컴파일 된 코드보다 느립니다. 해석 자체가 느릴뿐만 아니라 최적화를 수행하기가 더 어렵습니다. 그러나 코드에서 대부분의 시간을 라이브러리 함수 (Matlab의 경우)에 사용하면 성능이 저하되지 않습니다.
가상 머신 일부 언어는 bytecode 로 컴파일 된 다음 "머신 코드"로 해석되어 해석됩니다. 전형적인 예는 Java와 C #입니다. 바이트 코드는 기계 코드로 즉시 변환 될 수 있지만 코드는 여전히 느리게 실행됩니다. Java의 경우 가상 머신이 이식성을 위해 사용됩니다. C #의 경우 보안과 같은 다른 문제가있을 수 있습니다.
오버 헤드 일부 언어는 보안 효율성을 위해 거래합니다. 예를 들어, 파스칼의 일부 버전은 범위를 벗어난 배열에 액세스하지 않는지 확인합니다. C # 코드는 "관리"되며 비용이 듭니다. 또 다른 일반적인 예는 가비지 수집으로, 프로그래머의 시간은 절약하지만 메모리 관리에있어 효율적이지 않습니다. 예외 처리 또는 객체 지향 프로그래밍 지원을위한 인프라와 같은 다른 오버 헤드 소스가 있습니다.
* 사실, 요즘 고성능 시스템은 GPU에서, 심지어의 FPGA에서 코드를 실행합니다.
Y 대신 X를 선택하는 데는 여러 가지 요소가 있습니다.
일부 언어는 C # 또는 Python과 같은 비즈니스 프로젝트를 개발하는 데 적합하지만 다른 언어는 C ++과 같은 시스템 프로그래밍에 적합합니다.
어떤 플랫폼에서 작업 할 것인지와 어떤 응용 프로그램을 만들 것인지 결정해야합니다.
모든 플랫폼에서 얻을 수있는 "가장 빠른"프로그래밍 언어는 처리중인 칩셋의 어셈블리 언어입니다. 그 수준에는 번역이 없습니다. 그러나 칩셋이 명령을 실행하는 방법, 특히 병렬로 수행 할 수있는 명령에 대한 지식이 필요합니다.
C에서 어셈블리로의 변환은 일대일에 가깝지만 더 읽기 쉽다는 것은 매우 "얕다". 그러나 이식성을 향상시키는 표준 라이브러리로 인해 그 위에 많은 레이어가 있습니다. 어셈블리 코드에 도달하기 위해 컴파일러가 수행해야 할 작업이 많지 않으며 일반적으로 기계 별 변경을 위해 더 강력한 최적화가 있습니다.
C ++는 더 풍부한 언어를 추가합니다. 그러나 언어가 너무 복잡해지기 때문에 컴파일러가 플랫폼에 대한 최적의 코드를 작성하기가 더 어려워집니다.
그런 다음 저울의 다른쪽으로갑니다. 해석 된 언어. 작업을 수행하는 것 외에도 코드를 구문 분석하고이를 기계 호출로 변환하는 데 시간이 걸리기 때문에 속도가 가장 느립니다.
그런 다음 그 사이에있는 것들이 있습니다. 일반적으로 플랫폼에 최적화 된 가상 머신 계층이 있습니다. 그리고 컴파일러는 가상 머신이 실행할 코드를 생성합니다. 때때로 이것은 펄이나 파스칼, 루비 또는 파이썬처럼 한 번에 발생합니다. 또는 java와 같은 여러 단계에서.
이러한 가상 머신 중 일부는 JIT 컴파일러 개념을 추가하여 중간 바이트 코드를 변환하는 대신 머신 레벨 코드를 작성하여 런타임을 가속화합니다.
일부 가상 머신은 레벨이 낮아 바이트 코드에서 머신 코드로의 변환이 적습니다. 이식성을 유지하면서 속도를 높입니다.
*p++=*q++;
으로 많은 머신에서 와 동등한 머신 코드 가 더 빠르지 array1[i]=array2[i];
만 많은 프로세서에서 그 반대가 종종 발생하므로 컴파일러는 이전 스타일의 코드를 후자 (거의 "얕은"변환)로 변환 할 수 있습니다.
-O0
최적화를 수행하지 않는 경우입니다. 최적화는 컴파일러로 얻는 보너스이지만 언어 자체는 일대일 어셈블리로 번역 할 수 있습니다.
아직 언급되지 않은 요점은 일부 언어에서 동일한 코드를 여러 번 실행하면 항상 동일한 동작 시퀀스를 수행한다는 것입니다. 따라서 컴퓨터는 코드 섹션에서 수행해야 할 작업을 한 번만 결정하면됩니다. JavaScript의 "엄격한 사용"방언의 주요 이점 중 하나는 JavaScript 엔진이 일단 코드의 기능을 파악하면 다음에 실행될 때 해당 정보를 사용할 수 있다는 것입니다. "엄격한 사용"없이는 할 수 없습니다.
예를 들어, "엄격한 사용"이 없으면 다음과 같은 코드가 나타납니다.
function f() { return x; }
직접 호출 컨텍스트에서 변수 X를 리턴하거나 외부 호출 컨텍스트에서 변수 X를 리턴하거나 리턴 할 수 있습니다 Undefined
. 더 나쁜 것은 다음과 같은 루프입니다.
for (i=0; i<40; i+=1) { g(i); }
JavaScript 엔진 g()
이 i
[또는 g
그 문제 와 관련하여 무엇을 할 수 있는지 알 수있는 방법이 없습니다 . 문자열로 합법적으로 변경 g
되거나 i
변경 될 수 있기 때문에 i
JavaScript 엔진은 단순히 루프에서 숫자 추가 및 숫자 비교를 사용할 수 없지만 루프에서 각 함수 호출을 수행하여 함수 호출 중 하나 i
또는 g
. 대조적으로, "엄격한 사용"[일부 제정신] 방언에서 JavaScipt 엔진은 위의 코드를 검사하고 루프를 통과 할 때마다 동일한 숫자 변수를 사용하고 동일한 함수를 호출한다는 것을 알 수 있습니다. 따라서 식별 i
하고 작동 하기 만하면 됩니다.g
루프를 통과 할 때마다 찾아야하는 대신 시간을 크게 절약 할 수 있습니다.
여기에 꽤 전문적인 답변이 있습니다.이 답변은 가까이 있지 않지만 직관적입니다.
가능한 한 빨리 작업을 수행해야 할 때 어셈블리에서 실행하는 코드를 작성하려고한다고 여러 번 들었을 것입니다. 실제로 작업을 완료하는 데 필요한 명령 만 실행하기 때문입니다. 고급 언어에서는이 작업을 여러 줄로 구현할 수 있지만 컴파일러는 여전히이를 기계 언어로 번역해야합니다. 이 번역은 직접 작성할 수 있으므로 항상 최소한의 것은 아닙니다. 즉, 머신은 여분의 명령을 실행하는 데 많은 시간을 소비합니다.
오늘날 컴파일러는 매우 정교하지만 최고의 어셈블리 프로그래머가 할 수있는 것처럼 여전히 효과적이지 않습니다.
이 방향으로 계속해서, 불필요한 명령은 언어 수준이 높을수록 (보통) 양이 늘어납니다. (이것은 모든 고급 언어에 100 % 사실이 아닙니다)
따라서 특정 코드 조각의 경우 X의 기계어 코드가 Y보다 짧은 경우 언어 X는 언어 Y (런타임에서)보다 빠릅니다.
이 질문은 매우 복잡하고 다차원 적이므로 (예를 들어 기타 기준과 비교하여 자동차 브랜드를 비교하는 것과 비슷하기 때문에)이 질문에 결정적으로 답하기는 어렵지만 Rosetta 코드 ( wikipedia 개요 ) 라는 우수한 코드 저장소를 포함하여 새로운 과학적 연구가 있습니다 . Nanz와 Furia의 2014 년 설문 조사 는 다음과 같은 일반적인 기준과 일반적으로 주관적인 코드 품질에 대한 드문 정량적 분석을 바탕으로이 질문을 매우 명확하고 과학적으로 연구합니다. 초록에는 몇 가지 객관적인 결과와 일반화가 포함되어 있습니다. (이러한 결과에 대한 다른 연구가 향후에 이루어질 수 있기를 바랍니다.)
RQ1. 더 간결한 코드를 만드는 프로그래밍 언어는 무엇입니까?
RQ2. 어떤 프로그래밍 언어가 더 작은 실행 파일로 컴파일됩니까?
RQ3. 런타임 성능이 더 우수한 프로그래밍 언어는 무엇입니까?
RQ4. 어떤 프로그래밍 언어가 메모리를보다 효율적으로 사용합니까?
RQ5. 어떤 프로그래밍 언어는 실패가 덜 발생합니까?
초록 — 때로는 프로그래밍 언어에 대한 논쟁이 과학보다 종교적입니다. 어떤 언어가 더 간결하거나 효율적이거나 개발자의 생산성을 높이는가에 대한 질문은 열의로 논의되며 그들의 답변은 일화와 근거없는 신념에 너무 자주 근거합니다. 이 연구에서는 분석을 위해 큰 데이터 세트를 제공하는 다양한 언어의 공통 프로그래밍 작업에 대한 솔루션을 저장하는 코드 저장소 인 Rosetta Code의 잠재적 인 연구 잠재력을 사용합니다. 우리의 연구는 주요 프로그래밍 패러다임을 나타내는 8 가지 널리 사용되는 언어 (프로 시저 : C 및 Go; 객체 지향 : C # 및 Java; 기능 : F # 및 Haskell; 스크립팅 : Python 및 Ruby)에서 745 개의 태스크에 해당하는 7,087 개의 솔루션 프로그램을 기반으로합니다. 통계 분석 결과는 다음과 같습니다. 기능 및 스크립팅 언어는 절차 및 객체 지향 언어보다 간결합니다. 큰 입력에서 원시 속도에 관해서는 C가이기는 것이 어렵지만, 중간 크기의 입력에 대한 성능 차이는 덜 뚜렷하며 해석되는 언어조차 경쟁력이 있습니다. 컴파일 타임에 더 많은 결함이 발견 될 수있는 컴파일 된 강력한 형식의 언어는 해석되거나 약한 형식의 언어보다 런타임 오류가 덜 발생합니다. 개발자, 언어 디자이너 및 교육자에게 이러한 결과가 미치는 영향에 대해 논의합니다. 컴파일 타임에 더 많은 결함이 발견 될 수있는 경우 해석되거나 약한 유형의 언어보다 런타임 실패가 덜 발생합니다. 개발자, 언어 디자이너 및 교육자에게 이러한 결과가 미치는 영향에 대해 논의합니다. 컴파일 타임에 더 많은 결함이 발견 될 수있는 경우 해석되거나 약한 유형의 언어보다 런타임 실패가 덜 발생합니다. 개발자, 언어 디자이너 및 교육자에게 이러한 결과가 미치는 영향에 대해 논의합니다.
컴퓨터 언어는 컴퓨터가 무엇을해야하는지 설명하는 명령의 추상화 일뿐입니다.
컴퓨터 언어 Python
로 작성하여 C 컴파일러 (cython)로 컴파일 할 수도 있습니다.
컴퓨터 언어의 속도를 비교할 수는 없습니다.
그러나 동일한 언어의 컴파일러를 어느 정도 확장 할 수 있습니다. 예를 들어 GNU C
컴파일러와 Intel C
컴파일러. (컴파일러 벤치 마크 검색)