StackOverflow 팟 캐스트를 들으면서 b은 "실제 프로그래머"가 C로 작성하고 C가 "머신에 가깝기 때문에"훨씬 빠릅니다. 다른 게시물에 대한 이전 주장을 남겨두고 다른 언어보다 더 빠를 수있는 C의 특별한 점은 무엇입니까? 또는 다른 방법으로 말하면 다른 언어가 C만큼 빨리 실행되는 바이너리로 컴파일 할 수 없도록하는 것은 무엇입니까?
StackOverflow 팟 캐스트를 들으면서 b은 "실제 프로그래머"가 C로 작성하고 C가 "머신에 가깝기 때문에"훨씬 빠릅니다. 다른 게시물에 대한 이전 주장을 남겨두고 다른 언어보다 더 빠를 수있는 C의 특별한 점은 무엇입니까? 또는 다른 방법으로 말하면 다른 언어가 C만큼 빨리 실행되는 바이너리로 컴파일 할 수 없도록하는 것은 무엇입니까?
답변:
C에 대해서는 특별한 점이 많지 않습니다. 이것이 빠른 이유 중 하나입니다.
가비지 수집 , 동적 입력 및 기타 기능을 지원하는 최신 언어로 프로그래머가 프로그램을보다 쉽게 작성할 수 있습니다.
캐치에는 응용 프로그램의 성능을 저하시키는 추가 처리 오버 헤드가 있습니다. C에는 그 중 하나가 없으므로 오버 헤드가 없다는 것을 의미하지만 프로그래머는 메모리 누수 를 방지하기 위해 메모리 를 할당하고 해제 할 수 있어야합니다. 해야하며 변수의 정적 입력을 처리해야합니다.
즉, Java ( Java Virtual Machine 사용 ) 및 .NET (Common Language Runtime 사용)과 같은 많은 언어와 플랫폼 은 기본 기계 코드를 생성하는 JIT (Just-In-Time) 컴파일 과 같은 출현으로 수년 동안 성능이 향상되었습니다. 더 높은 성능을 달성하기 위해 바이트 코드.
C 디자이너가 만든 거래가 있습니다. 즉, 그들은 안전보다 속도를 높이기로 결정했습니다. C는하지 않습니다
Java로 배열에 색인을 생성하면 가상 시스템에서 일부 메소드 호출, 바운드 검사 및 기타 온 전성 검사가 필요합니다. 그것은 유효하고 절대적 으로 좋습니다. 왜냐하면 그것이 예정된 곳에 안전을 추가하기 때문입니다. 그러나 C에서는 아주 사소한 것조차 안전하지 않습니다. 예를 들어 C에서는 복사 할 영역이 겹치는 지 확인하기 위해 memcpy가 필요하지 않습니다. 그건 하지 큰 비즈니스 응용 프로그램을 프로그래밍하는 언어로 설계.
그러나 이러한 디자인 결정은 C 언어의 버그 가 아닙니다 . 컴파일러와 라이브러리 작성자가 컴퓨터에서 모든 성능을 얻을 수 있도록 설계되어 있습니다. 다음은 C 이론 문서에서 설명 하는 C 의 정신입니다 .
C 코드는 이식 할 수 없습니다. 프로그래머가 실제로 이식 가능한 프로그램을 작성할 수있는 기회를 제공하기 위해 노력했지만위원회는 프로그래머를 이식 가능하게 작성하여 C를``고수준 어셈블러 ''로 사용하는 것을 배제하기를 원하지 않았습니다. 코드는 C의 장점 중 하나입니다.
C의 정신을 유지하십시오. 위원회 는 C 의 전통적인 정신을 보존하기위한 주요 목표로 유지했습니다. C의 정신에는 여러 가지 측면이 있지만, 본질은 C 언어의 기반이되는 기본 원칙에 대한 공동체의 정서입니다. C의 정신의 일부 측면은 다음과 같은 문구로 요약 될 수 있습니다.
- 프로그래머를 신뢰하십시오.
- 프로그래머가 수행해야 할 작업을 방해하지 마십시오.
- 언어를 작고 단순하게 유지하십시오.
- 작업을 수행하는 한 가지 방법 만 제공하십시오.
- 휴대 성이 보장되지 않더라도 빨리 만드십시오.
마지막 잠언에는 약간의 설명이 필요합니다. 효율적인 코드 생성 가능성은 C의 가장 중요한 강점 중 하나입니다. 매우 간단한 작업으로 보이는 코드 폭발이 발생하지 않도록하기 위해 많은 작업이 대상 시스템의 하드웨어가 아닌 일반적인 추상 규칙. 기계가하는 것과 함께 살려는 이러한 의지의 예는 표현식에 사용하기 위해 char 객체의 확장을 결정하는 규칙에서 볼 수 있습니다. 대상 머신에서 효율적입니다.
한 달 동안 0.05 초 안에 실행되는 무언가를 빌드하고 Java로 같은 것을 쓰는 데 하루를 보내고 0.10 초 안에 실행하면 C가 더 빠릅니까?
그러나 귀하의 질문에 대답하기 위해, 잘 작성된 C 코드는 일반적으로 다른 언어로 작성된 잘 작성된 코드보다 빠르게 실행됩니다. C 코드 "잘 작성"의 일부에는 기계 근처에서 수동 최적화를 수행하는 것이 포함되기 때문입니다.
컴파일러는 실제로 매우 영리하지만, 여전히 손에 의한 알고리즘과 경쟁하는 코드를 창의적으로 만들 수는 없습니다 ( "손"이 우수한 C 프로그래머에 속한다고 가정 ).
편집하다:
많은 의견이 "C로 작성하고 최적화에 대해서는 생각하지 않습니다"라는 문구를 따릅니다.
델파이에서는 이것을 쓸 수 있습니다 :
function RemoveAllAFromB(a, b: string): string;
var
before, after :string;
begin
Result := b;
if 0 < Pos(a,b) then begin
before := Copy(b,1,Pos(a,b)-Length(a));
after := Copy(b,Pos(a,b)+Length(a),Length(b));
Result := before + after;
Result := RemoveAllAFromB(a,Result); //recursive
end;
end;
그리고 CI에서 이것을 작성하십시오 :
char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
for (j = 0; j < len2; j++) {
if (s1[i] == s2[j]) {
break;
}
}
if (j == len2) { /* s1[i] is not found in s2 */
*result = s1[i];
result++; /* assuming your result array is long enough */
}
}
그러나 C 버전에는 얼마나 많은 최적화가 있습니까? 우리는 델파이 버전에서 생각하지 않는 구현에 대해 많은 결정을합니다. 문자열은 어떻게 구현됩니까? 델파이에서는 보이지 않습니다. C에서는 ASCII 정수 배열에 대한 포인터가 될 것이라고 결정했습니다.이를 정수라고합니다. C에서는 한 번에 하나씩 문자 존재를 테스트합니다. 델파이에서는 Pos를 사용합니다.
그리고 이것은 단지 작은 예입니다. 큰 프로그램에서 C 프로그래머는 몇 줄의 코드로 이러한 종류의 낮은 수준의 결정을 내려야합니다. 수작업으로 제작 된 수작업으로 최적화 된 실행 파일을 추가합니다.
나는 그것을 보지 못 했으므로 말할 것입니다 : C는 거의 모든 것이 C로 작성되기 때문에 더 빠릅니다 .
Java는 C로, Python은 C (또는 Java 또는 .NET 등), Perl 등으로 작성됩니다. OS는 C로 작성되고 가상 머신은 C로 작성되고 컴파일러는 C로 작성됩니다. 인터프리터는 C로 작성됩니다. 일부는 여전히 어셈블리 언어로 작성되며, 속도가 훨씬 빠릅니다. 점점 더 많은 것들이 다른 것으로 작성되고 있으며, 그 자체가 C로 작성되었습니다.
어셈블리가 아닌 다른 언어로 작성하는 각 명령문은 일반적으로 C의 여러 명령문으로 구현되며 기본 머신 코드로 컴파일됩니다. C보다 더 높은 수준의 추상화를 얻기 위해 다른 언어가 존재하는 경향이 있기 때문에 C에 필요한 추가 설명은 안전성 추가, 복잡성 추가 및 오류 처리에 중점을 두는 경향이 있습니다. 그것들은 종종 좋은 것이지만, 비용이 있으며, 그 이름은 속도 와 크기 입니다.
개인적으로, 나는 가용 한 스펙트럼의 대부분에 걸쳐 문자 그대로 수십 개의 언어로 작성했으며, 개인적으로 당신이 암시하는 마술을 찾았습니다.
케이크도 먹고 먹을 수 있습니까? 내가 좋아하는 언어로 높은 수준의 추상화를 사용하여 연주하고 어떻게 C의 핵심에 빠뜨릴 수 있습니까?
몇 년의 연구 끝에 제 대답은 Python (C)입니다. 당신은 그것을보고 싶을 수도 있습니다. 그건 그렇고, 파이썬에서 어셈블리로 드롭 다운 할 수도 있습니다 (특별 라이브러리의 약간의 도움으로).
반면에 잘못된 코드는 모든 언어로 작성할 수 있습니다 . 따라서 C (또는 어셈블리) 코드는 자동으로 더 빠르지 않습니다 . 마찬가지로 일부 최적화 트릭은 고급 언어 코드의 일부 를 원시 C의 성능 수준에 가깝게 만들 수 있습니다. 그러나 대부분의 응용 프로그램에서 프로그램은 대부분의 시간을 사람이나 하드웨어를 기다리는 데 소비하므로 차이는 중요하지 않습니다.
즐겨.
거기에는 많은 질문이 있습니다. 대부분 대답 할 자격이없는 질문입니다. 그러나이 마지막 것에는 :
다른 언어가 C만큼 빨리 실행되는 바이너리로 컴파일 할 수 없도록하는 것은 무엇입니까?
한마디로 추상화.
C는 기계어에서 한 단계 또는 두 단계의 추상화입니다. Java 및 .Net 언어는 어셈블러에서 최소 3 단계 추상화 수준에 있습니다. 파이썬과 루비에 대해 잘 모르겠습니다.
일반적으로 프로그래머 장난감 (복잡한 데이터 유형 등)이 많을수록 기계 언어에서 멀어지고 더 많은 번역을 수행해야합니다.
나는 여기 저기 있지만 기본 요점입니다.
업데이트 -------이 게시물에 대한 자세한 설명이 있습니다.
C의 비용 모델이 투명 하기 때문에 C가 빠르지는 않습니다 . C 프로그램이 느리면 많은 문을 실행함으로써 명백한 방식으로 느려집니다. C의 작업 비용과 비교하여 객체 (특히 리플렉션) 또는 문자열에 대한 높은 수준의 작업은 명확하지 않은 비용을 가질 수 있습니다.
일반적으로 C만큼 빠른 바이너리로 컴파일되는 두 가지 언어는 표준 ML ( MLton 컴파일러 사용) 및 Objective Caml 입니다. 벤치 마크 게임 을 확인하면 바이너리 트리와 같은 일부 벤치 마크의 경우 OCaml 버전이 C보다 빠릅니다 (MLton 항목을 찾지 못했습니다). 그러나 총격을 너무 심각하게 생각하지 마십시오. 그것은 게임이 말했듯이 결과는 종종 사람들이 코드를 조정하는 데 얼마나 많은 노력을 기울 였는지 반영합니다.
C가 항상 빠르지는 않습니다.
C는 예를 들어 Modern Fortran보다 느립니다.
C는 종종 Java보다 느립니다. (특히 JIT 컴파일러가 코드를 살펴본 후)
C를 사용하면 포인터 앨리어싱이 가능해 지므로 일부 최적화가 불가능합니다. 특히 여러 실행 단위가있는 경우 데이터 가져 오기가 중단됩니다. 아야
포인터 산술이 작동한다고 가정하면 실제로 일부 CPU 제품군에서 부풀린 성능이 느려집니다 (특히 PIC!) 세그먼트 x86에서 큰 것을 빨아 들였습니다.
기본적으로 벡터 장치 또는 병렬화 컴파일러를 사용하면 C 악취와 최신 Fortran이 더 빨리 실행됩니다.
썽킹 (즉시 실행 파일 수정)과 같은 C 프로그래머 트릭으로 인해 CPU 프리 페치가 중단됩니다.
당신은 드리프트를 얻을?
그리고 우리의 좋은 친구 x86은 요즘 실제 CPU 아키텍처와 거의 관계가없는 명령어 세트를 실행합니다. 섀도우 레지스터,로드 저장소 최적화 프로그램은 모두 CPU에 있습니다. 따라서 C는 가상 금속에 가깝습니다. 진짜 금속, 인텔은 당신을 보지 못하게합니다. (역사적으로 VLIW CPU는 약간의 버스트이므로 아마도 그렇게 나쁘지 않을 것입니다.)
고성능 DSP (아마도 TI DSP?)에서 C로 프로그래밍하는 경우 컴파일러는 여러 병렬 실행 장치에서 C를 풀기 위해 까다로운 작업을 수행해야합니다. 이 경우 C는 금속에 가깝지 않지만 컴파일러에 가깝기 때문에 전체 프로그램 최적화가 수행됩니다. 기묘한.
마지막으로 일부 CPU (www.ajile.com)는 하드웨어에서 Java 바이트 코드를 실행합니다. C는 PITA가 해당 CPU에서 사용할 것입니다.
다른 언어가 C만큼 빨리 실행되는 바이너리로 컴파일 할 수 없도록하는 것은 무엇입니까?
아무것도. Java 또는 .NET 언어와 같은 최신 언어는 성능보다는 프로그래머 생산성에 더 중점을 둡니다. 하드웨어는 요즘 저렴합니다. 또한 중간 표현으로 컴파일하면 보안, 이식성 등과 같은 많은 보너스가 제공됩니다. .NET CLR은 다른 하드웨어를 활용할 수 있습니다. 예를 들어 SSE 명령어 세트를 사용하기 위해 프로그램을 수동으로 최적화 / 재 컴파일 할 필요가 없습니다.
주요 요소는 정적으로 형식화 된 언어이며 기계 코드로 컴파일된다는 것입니다. 또한 저수준 언어이기 때문에 일반적으로 말하지 않은 것은 없습니다.
이것들은 생각 나는 다른 요소들입니다.
대부분의 정적 유형 언어는 C보다 빠르거나 빠르게 컴파일 할 수 있습니다. 특히 포인터 별칭으로 인해 C가 할 수 없다고 가정 할 수있는 경우 특히 그렇습니다.
어셈블리 언어도 언어라는 것을 잊어 버린 것 같습니다 :)
그러나 진지하게, C 프로그램은 프로그래머가 자신이하는 일을 알고있을 때만 더 빠릅니다. 동일한 작업을 수행하는 다른 언어로 작성된 프로그램보다 느리게 실행되는 C 프로그램을 쉽게 작성할 수 있습니다.
C가 더 빠른 이유는 C가 이런 식으로 설계 되었기 때문입니다. 컴파일러가 코드를 최적화하는 데 도움이되는 많은 "낮은 수준"작업을 수행 할 수 있습니다. 또는 프로그래머가 코드를 최적화 할 책임이 있습니다. 그러나 종종 까다 롭고 오류가 발생하기 쉽습니다.
이미 언급 한 다른 언어와 같이 다른 언어는 프로그래머의 생산성에 더 중점을 둡니다. 프로그래머 시간은 기계 시간보다 훨씬 비싸다고 믿어집니다 (구시대에도). 따라서 프로그래머가 프로그램 실행 시간 대신 프로그램을 작성하고 디버깅하는 데 소요되는 시간을 최소화하는 것이 좋습니다. 그렇게하려면 많은 것들이 자동화되기 때문에 프로그램을 더 빨리 만들기 위해 할 수있는 일을 조금 희생해야합니다.
대부분의 경우 모든 C 명령어는 매우 적은 어셈블러 명령어에 해당합니다. 기본적으로 더 높은 수준의 기계 코드를 작성하므로 프로세서가 수행하는 거의 모든 것을 제어 할 수 있습니다. C ++과 같은 다른 많은 컴파일 된 언어에는 생각보다 훨씬 더 많은 코드로 변환 할 수있는 많은 간단한 명령어가 있습니다 (가상 함수, 복사 생성자 등). Java 또는 Ruby와 같은 해석되는 언어에는 다른 계층이 있습니다. 가상 머신 또는 인터프리터
C ++은 평균적으로 더 빠릅니다 (처음에는 약간의 차이가 있지만 C의 상위 집합이므로). 그러나 특정 벤치 마크의 경우 종종 더 빠른 다른 언어가 있습니다.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/
fannjuch-redux
스칼라에서 가장 빠른
n-body
그리고 fasta
빠른 에이다에 있었다.
spectral-norm
포트란에서 가장 빠릅니다.
reverse-complement
, mandelbrot
및 pidigits
ATS에서 가장 빠른했다.
regex-dna
JavaScript에서 가장 빠릅니다.
chameneou-redux
가장 빠른 것은 Java 7입니다.
thread-ring
Haskell에서 가장 빠릅니다.
나머지 벤치 마크는 C 또는 C ++에서 가장 빠릅니다.
extern "C"
C ++가 C의 상위 집합 이 되는 것과는 아무 관련이 없습니다 .
system("bash script.sh");
모든 bash 스크립트에서 작동하는 것과 같으므로 C는 bash의 상위 집합입니다. extern "C"
이름 맹 글링으로 인해 C ++에서 C 연결을 제공합니다. X를 Y의 수퍼 셋으로 호출하는 것은 Y에서 수행 할 수있는 모든 작업을 X에서도 수행 할 수 있음을 의미하지만 C ++에서는 그렇지 않습니다. C에서는 유효하지만 C ++에서는 유효하지 않은 언어 구성이 꽤 있습니다.
bash
에는 사용 가능한 명령 줄 프로그램 인 명령이 없습니다. 지원해야 할 bash의 버전 / 사양을 포함하고 포함했다면 상위 집합으로 간주됩니다.
struct foo { int: this; }; typedef float foo;
이러한 답변 중 많은 부분이 C가 더 빠르거나 그렇지 않은 이유에 대한 정당한 이유를 제시합니다 (일반적으로 또는 특정 시나리오에서). 다음과 같은 사실은 부인할 수 없습니다.
그럼에도 불구하고, 나는 다른 요소보다 C와 다른 많은 언어의 비교 성능에 더 크게 영향을 미친다는 것을 알았습니다. 재치 :
다른 언어는 종종 더 느리게 실행되는 코드를 작성하기가 더 쉽습니다. 종종 언어의 디자인 철학에 의해 장려되기도합니다. Corollary : C 프로그래머는 불필요한 작업을 수행하지 않는 코드를 작성할 가능성이 높습니다.
예를 들어, 단일 기본 창이 작성되는 간단한 Windows 프로그램을 고려하십시오. AC 버전은에 WNDCLASS[EX]
전달 될 구조를 채운 RegisterClass[Ex]
다음 CreateWindow[Ex]
메시지 루프 를 호출 하고 입력합니다. 매우 간단하고 축약 된 코드는 다음과 같습니다.
WNDCLASS wc;
MSG msg;
wc.style = 0;
wc.lpfnWndProc = &WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MainWndCls";
RegisterClass(&wc);
CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
C #의 동등한 프로그램은 한 줄의 코드 일 수 있습니다.
Application.Run(new Form());
이 한 줄의 코드는 거의 20 줄의 C 코드가 수행했던 모든 기능을 제공하며 오류 확인과 같은 몇 가지 기능을 추가합니다. 풍부하고 완전한 라이브러리 (일반적인 C 프로젝트에 사용 된 라이브러리와 비교)는 우리를 위해 많은 노력을 기울여 우리에게 짧아 보이지만 뒤에서 많은 단계를 포함하는 더 많은 코드 스 니펫을 작성할 시간을 자유롭게했습니다.
그러나 쉽고 빠른 코드 팽창을 가능하게하는 풍부한 라이브러리는 실제로 내 요점이 아닙니다. 우리의 작은 원 라이너가 실제로 실행될 때 실제로 일어나는 일을 검사하기 시작할 때 내 요점이 더 분명합니다. 언젠가는 재미를 위해 Visual Studio 2008 이상에서 .NET 소스 액세스 를 활성화 하고 위의 간단한 한 줄로 들어가십시오. 당신이 보게 될 재미있는 작은 보석 중 하나는 다음에 대한 getter의 주석입니다 Control.CreateParams
.
// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
//
if (createParams == null) {
createParams = new CreateParams();
}
열 번 . A의 저장 무슨의 합과 거의 비슷 정보 WNDCLASSEX
구조와 무엇에 전달 있어요 CreateWindowEx
로부터 검색되는 Control
클래스 열 시간 전에 그것이에 저장된 WNDCLASSEX
에게 구조와 전달 RegisterClassEx
및CreateWindowEx
.
이 기본적인 작업을 수행하기 위해 실행되는 명령의 수는 C보다 C에서 2 ~ 3 배 더 높습니다.이 중 일부는 기능이 풍부한 라이브러리를 사용하기 때문에 반드시 일반화됩니다. 우리가 필요로하는 것을 정확하게 수행하는 단순한 C 코드. 그러나 그 중 일부는 .NET 프레임 워크의 모듈화 된 객체 지향적 특성이 종종 절차 적 접근 방식으로 피할 수있는 많은 반복 실행에 적합하다는 사실에 기인합니다.
C # 또는 .NET 프레임 워크를 선택하려고하지 않습니다. 또한 모듈화, 일반화, 라이브러리 / 언어 기능, OOP 등은 나쁜 것 입니다. 나는 C에서 개발 한 대부분의 작업을 나중에 C ++에서, 그리고 가장 최근에는 C #에서 수행했다. 마찬가지로 C 이전에는 주로 어셈블리를 사용했습니다. 그리고 각 단계가 "더 높은"언어로 진행됨에 따라 단기간 내에 더 나은, 유지 보수가 용이하고보다 강력한 프로그램을 작성합니다. 그러나 그들은 조금 더 느리게 실행하는 경향이 있습니다.
Java를 제외하고 다른 컴파일러보다 C 컴파일러에 더 많은 노력을 기울 였다는 사실은 아무도 언급하지 않았다.
C는 거의 모든 다른 언어보다 이미 언급 된 여러 가지 이유로 극도로 최적화 할 수 있습니다. 따라서 다른 언어 컴파일러에 동일한 노력을 기울이면 C가 여전히 나올 것입니다.
노력보다 C보다 더 잘 최적화 할 수있는 후보 언어가 적어도 하나 있다고 생각하므로 더 빠른 이진을 생성하는 구현을 볼 수 있습니다. 제작자가 C보다 더 최적화 할 수있는 언어를 만들려고 노력했기 때문에 디지털 화성 D를 생각하고 있습니다.이 가능성이있는 다른 언어가있을 수 있습니다. 그러나 어떤 언어라도 컴파일러가 최고 C 컴파일러보다 몇 퍼센트 이상 빠를 것이라고 상상할 수 없습니다. 나는 틀리고 싶다.
실제 "낮은 교수형 과일"은 인간이 최적화하기 쉬운 언어로되어 있다고 생각합니다. 숙련 된 프로그래머는 모든 언어를 더 빠르게 만들 수 있습니다. 그러나 때로는 그렇게하기 위해 어리석은 일을하거나 부 자연스러운 구성을 사용해야합니다. 항상 노력을 기울일 것이지만, 좋은 언어는 프로그램 작성 방법을 정확하게 고집하지 않고도 비교적 빠른 코드를 생성해야합니다.
최악의 경우 코드가 빠르다는 점도 중요합니다 (적어도 나에게는). 웹에는 Java가 C보다 빠르거나 빠르다는 수많은 "증거"가 있지만 이는 체리 따기 예제를 기반으로합니다. 나는 C의 열렬한 팬은 아니지만 C로 쓰는 것은 잘 작동한다는 것을 알고 있습니다. Java를 사용하면 속도의 15 %, 보통 25 % 내에서 "아마도"실행되지만 경우에 따라 훨씬 더 나빠질 수 있습니다. 그것이 빠르거나 몇 퍼센트 안에 빠르는 경우는 대개 어쨌든 C에 최적화 된 라이브러리 코드에서 대부분의 시간을 소비하기 때문입니다.
이것은 실제로 약간의 허위 사실입니다. C 프로그램이 더 빠르다는 것은 사실이지만 특히 C 프로그래머가 그다지 능숙하지 않은 경우에는 항상 그런 것은 아닙니다.
사람들이 잊어 버리는 큰 눈부신 구멍은 프로그램이 GUI 프로그램의 사용자 입력과 같은 일종의 IO를 차단해야 할 때입니다. 이러한 경우 데이터를 처리 할 수있는 속도가 아니라 데이터가 들어오는 속도에 의해 제한되므로 사용하는 언어는 중요하지 않습니다. 이 경우 C, Java, C # 또는 심지어 Perl을 사용하더라도 중요하지 않습니다. 데이터가 들어오는 것보다 더 빨리 갈 수는 없습니다.
다른 중요한 것은 가비지 수집을 사용하고 적절한 포인터를 사용하지 않으면 가상 컴퓨터가 다른 언어로는 사용할 수없는 여러 가지 최적화를 수행 할 수 있다는 것입니다. 예를 들어, JVM은 조각 모음을 위해 힙에서 오브젝트를 이동시킬 수 있습니다. 따라서 다음 인덱스를 테이블에서 찾아 보지 않고 간단히 사용할 수 있으므로 향후 할당이 훨씬 빨라집니다. 최신 JVM도 실제로 메모리 할당을 해제 할 필요가 없습니다. 대신, 그들은 GC를 할 때 라이브 객체를 움직이고 죽은 객체에서 사용한 메모리는 본질적으로 무료로 복구됩니다.
이것은 또한 C에 대한 흥미로운 점을 제시하고 C ++에서는 훨씬 더 중요합니다. "필요하지 않으면 비용을 지불하지 않는다"는 디자인 철학이 있습니다. 문제는 당신이 원한다면 코를 통해 돈을 지불하게된다는 것입니다. 예를 들어 Java의 vtable 구현은 C ++ 구현보다 훨씬 나은 경향이 있으므로 가상 함수 호출이 훨씬 빠릅니다. 반면에 Java에서 가상 기능을 사용하는 것 외에는 선택의 여지가 없으며 여전히 비용이 많이 들지만 많은 가상 기능을 사용하는 프로그램에서는 비용이 절감됩니다.
도구와 라이브러리만큼 언어에 관한 것이 아닙니다. C에 사용 가능한 라이브러리 및 컴파일러는 최신 언어보다 훨씬 오래되었습니다. 이것이 느려질 것이라고 생각할 수도 있지만 반대입니다.
이 라이브러리는 처리 능력과 메모리가 중요한 시점에 작성되었습니다. 그들은 일을하기 위해 매우 효율적 으로 작성되어야 했습니다. C 컴파일러 개발자는 다른 프로세서에 대한 모든 종류의 영리한 최적화 작업에 오랜 시간을 보냈습니다. C의 성숙도와 폭 넓은 채택으로 인해 같은 연령의 다른 언어에 비해 큰 이점이 있습니다. 또한 C만큼 필요한 원시 성능을 강조하지 않는 최신 도구보다 C에 속도 이점을 제공합니다.
오래된 "C / C ++ 는 Java보다 해석이 빠르므로 Java보다 빠릅니다"라는 신화는 여전히 살아 있습니다. 몇 년 전의 기사 와 최신 기사 가 있지만 , 이것이 왜 항상 그렇지는 않는지 개념이나 측정으로 설명 합니다 .
현재 가상 머신 구현 (그리고 JVM뿐만 아니라)은 다양한 기술을 사용하여 프로그램 실행 중 수집 된 정보를 활용하여 코드가 실행될 때 동적으로 튜닝 할 수 있습니다.
및 대한 기타 조정의 다양한 코드가 실제로 무엇을하고 있는지 알고 기반으로, 그것은 실행중인되는 환경의 실제 특성에.
가장 빠른 실행 코드는 수작업으로 제작 된 기계 코드입니다. 어셈블러는 거의 비슷할 것입니다. 둘 다 매우 낮은 수준이며 작업을 수행하는 데 많은 코드를 작성해야합니다. C는 어셈블러보다 약간 높습니다. 실제 머신에서는 여전히 매우 낮은 레벨로 사물을 제어 할 수 있지만 추상화가 충분하여 어셈블러보다 빠르고 쉽게 작성할 수 있습니다. C # 및 JAVA와 같은 다른 언어는 훨씬 더 추상적입니다. 어셈블러 및 기계어 코드를 저수준 언어라고하는 반면 C # 및 JAVA (및 기타 여러 언어)를 고수준 언어라고합니다. C는 때때로 중급 언어라고합니다.
다른 사람의 말을 들지 말고 코드의 성능 결정 부분에서 C와 선택 언어 모두에 대한 디스 어셈블리를 살펴보십시오. Visual Studio에서 런타임에 디스 어셈블리 창에서 디스 어셈블 된 .Net을 볼 수 있다고 생각합니다. windbg를 사용하여 Java에 까다로운 경우 가능해야하지만 .Net으로 수행하면 많은 문제가 동일합니다.
필요하지 않으면 C로 쓰는 것을 좋아하지 않지만 C가 아닌 다른 언어의 속도를 단순히 C에서 동일한 루틴을 분해하여 무시할 수 있다고 주장하는이 답변에서 제기 된 많은 주장을 생각합니다. 특히 성능에 중요한 응용 프로그램에서 일반적으로 사용되는 많은 양의 데이터가 포함 된 경우 더 높은 수준의 언어를 선택해야합니다. Fortran은 전문 분야에서 예외 일 수 있습니다. C보다 높은 레벨입니까?
JITed 코드와 네이티브 코드를 처음 비교했을 때 .Net 코드가 C 코드와 비교할 수 있는지 여부에 대한 모든 질문이 해결되었습니다. 추가적인 추상화 수준과 모든 안전 점검에는 상당한 비용이 듭니다. Java에 동일한 비용이 적용될 수는 있지만 성능에 중요한 부분을 시도해보십시오. (누구나 JITed Java에 대해 메모리에서 컴파일 된 프로 시저를 찾을만큼 충분한 지식이 있습니까? 확실히 가능해야합니다.)
1) 다른 사람들이 말했듯이 C는 당신을 위해 덜합니다. 초기화 변수, 배열 경계 검사, 메모리 관리 등이 없습니다. 다른 언어의 이러한 기능에는 C가 사용하지 않는 메모리 및 CPU주기가 필요합니다.
2) C가 덜 추상화되어 더 빠르다는 대답은 절반 만 맞습니다. 기술적으로 말하자면, 언어 X에 대해 "충분히 고급 컴파일러"를 사용한다면 언어 X는 C의 속도에 근접하거나 동일 할 수 있습니다. 순진한 컴파일러조차도 괜찮은 일을 할 수있는 어셈블리 언어에 직접. 파이썬과 같은 경우에는 가능한 유형의 객체를 예측하고 기계 코드를 즉석에서 생성하는 고급 컴파일러가 필요합니다 .C의 의미는 간단한 컴파일러가 잘 수행 할 수있을만큼 간단합니다.
좋은 시대로 돌아가서, 컴파일과 해석의 두 가지 언어가있었습니다.
컴파일 된 언어는 "컴파일러"를 사용하여 언어 구문을 읽고이를 CPU에서 직접 사용할 수있는 동일한 어셈블리 언어 코드로 변환했습니다. 해석 된 언어는 서로 다른 두 가지 체계를 사용했지만 기본적으로 언어 구문은 중간 형식으로 변환 된 다음 코드를 실행하기위한 환경 인 "통역사"에서 실행됩니다.
따라서 어떤 의미에서 코드와 기계 사이에 또 다른 "계층"(인터프리터)이있었습니다. 또한 컴퓨터에서 항상 그렇듯이 더 많은 리소스가 사용됩니다. 통역사는 더 많은 작업을 수행해야했기 때문에 속도가 느 렸습니다.
최근에는 컴파일러와 인터프리터를 모두 사용하는 Java와 같은 하이브리드 언어가 더 많이 작동했습니다. 복잡하지만 JVM은 이전 인터프리터보다 더 빠르고 정교하며 최적화되어 있으므로 컴파일 된 코드에 가깝게 수행하는 시간이 지남에 따라 훨씬 더 나은 변화를 나타냅니다. 물론 최신 컴파일러에는 더 멋진 최적화 트릭이 있으므로 이전보다 더 나은 코드를 생성하는 경향이 있습니다. 그러나 대부분의 최적화는 항상 (항상 그런 것은 아니지만) 일부 상황에서 항상 모든 상황에서 더 빠르지는 않은 유형의 상충 관계를 만듭니다. 다른 모든 것들과 마찬가지로 무료는 제공되지 않으므로 옵티마이 저는 어딘가에서 자랑해야합니다 (종종 컴파일 타임 CPU를 사용하여 런타임 CPU를 절약하는 경우도 있음).
C로 돌아 가면 간단한 언어로, 최적화 된 어셈블리로 컴파일 한 다음 대상 컴퓨터에서 직접 실행할 수 있습니다. C에서 정수를 늘리면 CPU에서 하나의 어셈블러 단계 일 가능성이 높지만 Java에서는 그보다 훨씬 많은 결과가 발생할 수 있습니다 (가비지 수집도 포함 할 수 있음 : -) C는 기계에 더 가까운 추상화를 제공하지만 (어셈블러가 가장 가깝습니다) 결국에는 더 많은 작업을 수행해야하며 보호되거나 사용하기 쉽거나 오류 친화적이지 않습니다. 대부분의 다른 언어는 더 높은 추상화를 제공하고 더 많은 기본 세부 사항을 처리하지만 고급 기능과 교환하려면 더 많은 리소스가 필요합니다. 일부 솔루션을 일반화 할 때 더 넓은 범위의 컴퓨팅을 처리해야합니다.
폴
++i
"add [ebp-8], 1"로 컴파일 할 수 있습니다. 페치, 증가, 저장은 여전히 일어나지 않지만 CPU에 의해 처리되며 Paul이 말한 것처럼 단지 하나의 명령입니다.
핫스팟 최적화 , 사전 컴파일 된 메타 알고리즘 및 다양한 형태의 병렬 처리 와 같은 고급 최적화 기술을 제외 하고 언어의 기본 속도 는 일반적으로 수행되는 작업을 지원하는 데 필요한 암시 적 배후 복잡성 과 밀접한 관련이 있습니다. 내부 루프 내에 지정되어야합니다 .
아마도 가장 분명한 것은 포인터 null
검사 및 배열 경계에 대한 인덱스 확인과 같은 간접 메모리 참조에 대한 유효성 검사입니다 . 대부분의 고급 언어는 이러한 검사를 암시 적으로 수행하지만 C는 수행하지 않습니다. 그러나 이것이 반드시 다른 언어의 근본적인 한계는 아닙니다 . 충분히 영리한 컴파일러는 어떤 형태의 루프 불변 코드 모션을 통해 알고리즘의 내부 루프에서 이러한 검사를 제거 할 수 있습니다 .
C의 더 근본적인 장점 (그리고 밀접하게 관련된 C ++과 유사한 정도)은 스택 기반 메모리 할당 에 크게 의존하고 있으며, 이는 본질적으로 할당, 할당 해제 및 액세스에 빠릅니다 . C (및 C ++)에서 기본 호출 스택 은 기본 요소, 배열 및 집계 ( struct
/class
)의 .
C는 동적으로 할당 하는 기능을 제공하지만 임의의 크기와 수명의 메모리 (소위 '힙'사용)을 제공하지만 기본적으로 그렇게하지 않습니다 (스택이 대신 사용됨).
감탄스럽게도 때로는 다른 프로그래밍 언어의 런타임 환경 내에서 C 메모리 할당 전략을 복제 할 수 있습니다. C 또는 C ++로 작성된 코드를 JavaScript의 서브 세트로 변환하고 웹 브라우저 환경에서 거의 기본 속도로 안전하게 실행할 수있는 asm.js 에 의해 증명되었습니다 .
제쳐두고, C와 C ++가 속도를 위해 대부분의 다른 언어를 능가하는 또 다른 영역은 기본 기계 명령어 세트와 매끄럽게 통합 할 수있는 능력입니다. 주목할만한 예는 SIMD 내장 함수 의 (컴파일러 및 플랫폼에 따라 다름) 가용성 으로, 현재 거의 보편적으로 사용되는 병렬 처리 하드웨어를 활용하는 사용자 정의 알고리즘 구성을 지원하는 동시에 언어에서 제공하는 데이터 할당 추상화 (낮은 수준)를 활용합니다. 레벨 레지스터 할당은 컴파일러에 의해 관리됩니다).
왜 일부 언어가 더 빠르며 일부는 더 느린 지에 대한 링크에서 답변을 찾았습니다. 왜 이것이 C 또는 C ++가 다른 언어보다 빠른지에 대해 더 명확하게하기를 희망합니다 .C보다 빠른 다른 언어도 있지만 우리는 할 수 없습니다 그들 모두를 사용하십시오. 일부 설명-
Fortran이 여전히 중요한 주요 이유 중 하나는 빠르기 때문입니다. Fortran으로 작성된 번호 크 런칭 루틴은 대부분의 다른 언어로 작성된 동등한 루틴보다 빠릅니다. 이 영역에서 Fortran과 경쟁하는 언어 (C 및 C ++)는이 성능과 경쟁하기 때문에 사용됩니다.
이것은 질문을 제기합니다 : 왜? C ++과 Fortran이 빠른 이유는 무엇이며 Java 또는 Python과 같은 다른 인기있는 언어보다 우수한 이유는 무엇입니까?
해석 및 컴파일 프로그래밍 스타일과 제안하는 기능에 따라 프로그래밍 언어를 분류하고 정의하는 방법에는 여러 가지가 있습니다. 성능을 볼 때 가장 큰 단일 차이점은 해석 된 언어와 컴파일 된 언어 간의 차이입니다.
나누기는 어렵지 않다. 오히려 스펙트럼이 있습니다. 한쪽에는 포트란, C 및 C ++를 포함하는 그룹 인 전통적인 컴파일 된 언어가 있습니다. 이러한 언어에는 프로그램의 소스 코드를 프로세서가 사용할 수있는 실행 가능한 형식으로 변환하는 개별 컴파일 단계가 있습니다.
이 컴파일 프로세스에는 여러 단계가 있습니다. 소스 코드가 분석되고 구문 분석됩니다. 이 시점에서 오타 및 철자 오류와 같은 기본 코딩 오류가 감지 될 수 있습니다. 구문 분석 된 코드는 메모리 내 표현을 생성하는 데 사용되며,이 기능은 존재하지 않는 함수 호출 또는 텍스트 문자열에서 산술 연산을 수행하는 등의 실수를 감지하는 데에도 사용될 수 있습니다.
이 메모리 내 표현은 실행 코드를 생성하는 부분 인 코드 생성기를 구동하는 데 사용됩니다. 생성 된 코드의 성능을 향상시키기위한 코드 최적화는이 프로세스 내에서 다양한 시간에 수행됩니다. 코드 표현에 대해 높은 수준의 최적화가 수행 될 수 있으며 코드 생성기의 출력에는 하위 수준의 최적화가 사용됩니다.
실제로 코드를 실행하면 나중에 발생합니다. 전체 컴파일 프로세스는 단순히 실행할 수있는 것을 만드는 데 사용됩니다.
반대편에는 통역사가 있습니다. 인터프리터에는 컴파일러와 유사한 구문 분석 단계가 포함되지만 프로그램이 즉시 실행되는 직접 실행을 유도하는 데 사용됩니다.
가장 간단한 인터프리터는 언어가 지원하는 다양한 기능에 해당하는 실행 가능한 코드를 가지고 있습니다. 따라서 주어진 언어에 관계없이 숫자를 추가하고, 문자열을 조인하는 기능이 있습니다. 코드를 구문 분석 할 때 해당 기능을 찾아서 실행합니다. 프로그램에서 생성 된 변수는 이름을 데이터에 매핑하는 일종의 조회 테이블에 보관됩니다.
인터프리터 스타일의 가장 극단적 인 예는 배치 파일 또는 셸 스크립트와 같은 것입니다. 이러한 언어에서, 실행 코드는 종종 인터프리터 자체에 내장되지 않고 독립된 독립형 프로그램입니다.
그렇다면 왜 이것이 성능에 차이가 있습니까? 일반적으로 각 간접 계층은 성능을 저하시킵니다. 예를 들어, 두 개의 숫자를 추가하는 가장 빠른 방법은 프로세서의 레지스터에 해당 숫자를 모두 두어 프로세서의 추가 명령어를 사용하는 것입니다. 이것이 컴파일 된 프로그램이 할 수있는 일입니다. 변수를 레지스터에 넣고 프로세서 명령어를 활용할 수 있습니다. 그러나 해석 된 프로그램에서 동일한 추가를 수행하려면 추가 할 값을 가져오고 추가를 수행하기 위해 함수를 호출하기 위해 변수 테이블에서 두 개의 조회가 필요할 수 있습니다. 이 함수는 컴파일 된 프로그램이 실제 추가를 수행하는 데 사용하는 것과 동일한 프로세서 명령어를 잘 사용할 수 있지만 실제로 명령어를 사용하기 전에 수행되는 모든 추가 작업으로 인해 속도가 느려집니다.
더 알고 싶다면 소스 를 확인하십시오
일부 C ++ 알고리즘은 C보다 빠르며 다른 언어의 알고리즘 또는 디자인 패턴 구현은 C보다 빠를 수 있습니다.
사람들이 C가 빠르다고 말하고 다른 언어에 대해 이야기 할 때 일반적으로 C의 성능을 벤치 마크로 사용합니다.
최신 최적화 컴파일러를 사용하면 순수한 C 프로그램이 컴파일 된 .net 코드보다 훨씬 빠를 가능성은 거의 없습니다. .net과 같은 프레임 워크가 개발자에게 제공하는 생산성 향상을 통해 일반 C에서 몇 주 또는 몇 달이 걸리던 작업을 하루에 수행 할 수 있습니다. 개발자의 월급과 비교할 때 저렴한 하드웨어 비용과 결합하면 그저 길입니다 쓰기로 저렴 고급 언어로 물건을 느리게하고 하드웨어를 던지십시오.
Jeff와 Joel이 C를 "실제 프로그래머"언어라고 말하는 이유는 C에 손을 잡고 있지 않기 때문입니다. 자신의 메모리를 할당하고, 메모리를 할당 해제하고, 자신의 경계 검사를 수행해야합니다. 새로운 객체 (); 가비지 수집, 클래스, OOP, 엔터티 프레임 워크, LINQ, 속성, 특성, 필드 또는 이와 유사한 것은 없습니다. 포인터 산술과 포인터 역 참조 방법 등을 알아야합니다. 그리고 그 문제에 대해 포인터가 무엇인지 알고 이해하십시오. 스택 프레임이 무엇인지, 명령어 포인터가 무엇인지 알아야합니다. 작업중인 CPU 아키텍처의 메모리 모델을 알아야합니다. 마이크로 컴퓨터의 아키텍처에 대한 암묵적인 이해가 많이 있습니다 (일반적으로 은C에서 프로그래밍 할 때 C #이나 Java와 같은 프로그래밍 할 때 단순히 존재하지 않거나 필요하지 않은 마이크로 컴퓨터. 이 모든 정보는 컴파일러 (또는 VM) 프로그래머에게 오프로드되었습니다.
자동 언어와 수동 언어의 차이점은 고급 언어가 추상화되어 자동화 된 것입니다. C / C ++는 수동으로 제어 및 처리되며, 오류 검사 코드도 수동 작업입니다.
C와 C ++는 컴파일 된 언어로, 어느 곳에서나 비즈니스를 수행 할 수있는 것은 아니며, 이러한 언어는 사용하는 하드웨어에 맞게 조정해야하므로 추가 계층을 추가해야합니다. C / C ++ 컴파일러가 모든 플랫폼에서 점점 일반화되면서 현재는 약간 희미 해지고 있습니다. 플랫폼간에 크로스 컴파일을 수행 할 수 있습니다. 여전히 모든 상황에서 실행되는 것은 아닙니다. 기본적으로 컴파일러 A에게 컴파일러 B와 동일한 코드를 다른 아키텍처로 컴파일하도록 지시합니다.
결론 C 언어는 이해하기 쉽지 않으며 추론하기위한 것이 아니며 시스템 언어라고도합니다. 그들은이 모든 높은 수준의 추상화 넌센스 이전에 나왔습니다. 이것이 또한 프론트 엔드 웹 프로그래밍에 사용되지 않는 이유입니다. 그것들은 단지 작업에 적합하지 않았으며, 기존 언어 툴로는 해결할 수없는 복잡한 문제를 해결하는 수단입니다.
이것이 바로 마이크로 아키텍처, 드라이버, 양자 물리학, AAA 게임, 운영 체제와 같은 미친 것들을 얻는 이유입니다 .C와 C ++가 적합합니다. 속도 및 수 크 런칭이 주요 영역입니다.
C는 기본적으로 컴파일 된 저수준 언어이기 때문에 빠릅니다. 그러나 C가 가장 빠르지는 않습니다. 재귀 피보나치 벤치 마크 쇼 녹, 크리스탈, 그리고 님은 빠를 수있다.
다음과 같은 여러 가지 이유가 있습니다.