在收听StackOverflow播客时,戳记不断出现,“真正的程序员”用C编写,而且C快得多,因为它“靠近机器”。将前一个断言放到另一篇文章中,C有什么特别之处,它可以使其比其他语言更快?或换种说法:是什么阻止其他语言能够编译为与C一样快的二进制文件?
在收听StackOverflow播客时,戳记不断出现,“真正的程序员”用C编写,而且C快得多,因为它“靠近机器”。将前一个断言放到另一篇文章中,C有什么特别之处,它可以使其比其他语言更快?或换种说法:是什么阻止其他语言能够编译为与C一样快的二进制文件?
Answers:
C没什么特别的。这就是为什么它很快的原因之一。
较新的语言支持垃圾回收,动态类型化和其他功能,使程序员可以更轻松地编写程序。
问题是,存在额外的处理开销,这将降低应用程序的性能。C没有任何这些,这意味着没有开销,但是这意味着程序员需要能够分配内存并释放它们以防止内存泄漏,并且必须处理变量的静态类型。
就是说,许多语言和平台,例如Java(带有Java虚拟机)和.NET(带有公共语言运行时),随着诸如即时编译等技术的出现,多年来已经出现了改进,即时编译可以从本地生成本地机器代码。字节码以实现更高的性能。
C设计师需要权衡取舍。也就是说,他们决定将速度置于安全之上。C不会
当您索引数组时,在Java中,它需要在虚拟机中进行一些方法调用,绑定检查和其他健全性检查。这是正确且绝对正确的,因为这样可以增加安全性。但是在C语言中,即使是非常琐碎的事情也没有放在安全性中。例如,C不需要memcpy检查要复制的区域是否重叠。它不是设计用于编写大型业务应用程序的语言。
但是这些设计决策并不是C语言中的错误。它们是设计使然,因为它允许编译器和库编写器从计算机中获得所有性能。这是C的精神,C Rationale文档如何解释它:
C代码可以是不可移植的。尽管尽力为程序员提供编写真正可移植程序的机会,但委员会不想强迫程序员进行可移植的编写,以排除使用C作为``高级汇编程序''的能力:即编写特定于机器的功能代码是C的优势之一。
保持C的精神。委员会一直将保留C的传统精神作为主要目标。C的精神有很多方面,但是本质是C语言所基于的基本原则的社区观点。C精神的某些方面可以概括为
- 相信程序员。
- 不要阻止程序员去做需要做的事情。
- 保持语言小而简单。
- 仅提供一种执行操作的方法。
- 即使不能保证可移植,也要使其快速。
最后的谚语需要一点解释。高效代码生成的潜力是C语言最重要的优势之一。为了帮助确保看似非常简单的操作不会发生代码爆炸,许多操作被定义为目标计算机硬件的工作方式,而不是通过一般的抽象规则。这种愿意忍受机器所做的事情的例子可以从控制用于表达式的char对象扩展的规则中看出:char对象的值是扩展为有符号数还是无符号数通常取决于哪个字节操作更多在目标机器上高效。
如果您花一个月的时间用0.05秒在C中构建某些东西,而我花一天的时间用Java编写相同的东西,并且它在0.10秒内运行,那么C真的更快吗?
但是要回答您的问题,编写良好的 C代码通常会比其他语言编写良好的代码运行更快,因为编写“良好”的C代码的一部分包括在接近机器级别进行手动优化。
尽管编译器确实非常聪明,但是他们还不能创造性地提出与手动算法竞争的代码(假设“手”属于优秀的 C程序员)。
编辑:
很多评论都遵循“我用C语言编写,我不考虑优化”的思路。
但是以这篇文章为例:
在Delphi中,我可以这样写:
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版本有多少优化?我们在实现方面做出了很多决策,而我在Delphi版本中没有考虑过。字符串如何实现?在Delphi中,我看不到它。在C语言中,我确定它将是指向ASCII整数数组的指针,我们将其称为chars。在C语言中,我们一次测试一个字符是否存在。在Delphi中,我使用Pos。
这只是一个小例子。在大型程序中,C程序员必须每隔几行代码就做出这类低级决策。它加起来是一个手工制作,经过手工优化的可执行文件。
我还没有看到它,所以我要说: C趋向于更快,因为几乎所有其他内容都是用C编写的。
Java是基于C的,Python是基于C(或Java或.NET等)的,Perl等。操作系统是用C编写的,虚拟机是用C编写的,编译器是用C编写的,解释程序是用C编写的。有些东西仍然是用汇编语言编写的,这往往会更快。越来越多的东西正在用其他方式编写,而其他本身就是用C编写的。
您用其他语言(而不是程序集)编写的每个语句通常在C中以多个语句的形式实现,这些语句被编译为本机代码。由于倾向于使用那些其他语言来获得比C更高的抽象级别,因此C中所需的那些额外语句倾向于将重点放在增加安全性,增加复杂性和提供错误处理上。这些通常是好东西,但它们有成本,而且它的名称是速度和大小。
就我个人而言,我实际上使用了数十种语言,涵盖了大多数可用频谱,并且我个人一直在寻求您所暗示的魔力:
我怎么也可以吃蛋糕?我该如何使用自己喜欢的语言来进行高级抽象处理,然后再考虑C的实质,以提高速度?
经过几年的研究,我的答案是Python(在C上)。您可能想看看。顺便说一句,您也可以从Python下拉到Assembly(在特殊库的帮助下)。
另一方面,错误的代码可以用任何语言编写。因此,C(或汇编)代码不会自动更快。同样,一些优化技巧可以使高级语言代码的某些部分接近原始C的性能水平。但是,对于大多数应用程序,您的程序将大部分时间都花在等待人或硬件上,因此区别实际上并不重要。
请享用。
那里有很多问题-大多数是我没有资格回答的问题。但是对于这最后一个:
是什么使其他语言无法编译成可以像C一样快的二进制代码运行?
总之,抽象。
C仅是远离机器语言的一两个抽象级别。Java和.Net语言至少要远离汇编程序3个抽象级别。我不确定Python和Ruby。
通常,程序员玩弄的越多(复杂的数据类型等),您与机器语言的距离就越远,并且需要完成的翻译越多。
我到处都是,但这是基本要点。
更新 -------这篇文章有一些不错的评论,有更多详细信息。
由于C的成本模型是透明的,因此C的速度并不快。如果C程序很慢,那么它显然很慢:通过执行很多语句。与C语言中的操作成本相比,对对象(尤其是反射)或字符串的高级操作所带来的成本并不明显。
通常可以编译为与C一样快的二进制文件的两种语言是Standard 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将在该CPU上使用PITA。
是什么使其他语言无法编译成可以像C一样快的二进制代码运行?
没有。诸如Java或.NET lang之类的现代语言更注重程序员的工作效率,而不是性能。如今,硬件便宜。此外,以中间表示形式进行编译还会带来很多好处,例如安全性,可移植性等。.NETCLR可以利用不同的硬件-例如,您无需手动优化/重新编译程序即可使用SSE指令集。
主要因素是它是一种静态类型的语言,并且已编译为机器代码。另外,由于它是一种低级语言,因此它通常不会做您没有告诉它的任何事情。
这些是我想到的其他一些因素。
不过,大多数静态类型的语言可以比C更快或更快速地编译,尤其是当它们可以假设C由于指针别名等原因而不能编译时。
我猜你忘了汇编语言也是一种语言:)
但是严重的是,仅当程序员知道自己在做什么时,C程序才会更快。您可以轻松地编写一个C程序,该程序的运行速度比用其他语言完成相同任务的程序慢。
C之所以更快,是因为它是按这种方式设计的。它使您可以执行许多“较低级别”的工作,以帮助编译器优化代码。或者,我们应该说,您是程序员负责优化代码。但这通常很棘手且容易出错。
像已经提到的其他语言一样,其他语言则更多地关注程序员的生产力。通常认为,程序员的时间比机器的时间(甚至在过去)要贵得多。因此,最大限度地减少程序员在编写和调试程序上的时间,而不是在程序的运行时间上,具有很大的意义。要做到这一点,您将牺牲一些精力来使程序更快,因为很多事情都是自动化的。
在大多数情况下,每个C指令都对应于很少的汇编程序指令。您实质上是在编写更高级别的机器代码,因此您几乎可以控制处理器的所有工作。许多其他编译语言,例如C ++,具有许多看起来很简单的指令,它们可以转换成比您认为的要多的代码(虚拟函数,副本构造函数等。)而Java或Ruby之类的解释语言则具有另外一层您从未见过的说明-虚拟机或解释器。
C ++的平均速度要快一些(尽管最初是C的超集,尽管存在一些差异)。但是,对于特定的基准测试,通常存在另一种更快的语言。
https://benchmarksgame-team.pages.debian.net/benchmarksgame/
fannjuch-redux
在Scala最快
n-body
并且fasta
在Ada更快。
spectral-norm
在Fortran中最快。
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语言与许多其他语言的比较性能的影响更大。以机智:
其他语言通常使编写执行速度较慢的代码更容易。通常,它甚至受到语言的设计哲学的鼓舞。结论: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();
}
十次。从类中检索大约等于WNDCLASSEX
结构中存储的内容和传递给什么的总和的信息,然后再将其存储在结构中并传递给and 十次。CreateWindowEx
Control
WNDCLASSEX
RegisterClassEx
CreateWindowEx
总而言之,在C#中执行该基本任务所执行的指令数量比在C中要多2–3个数量级。部分原因是由于使用了功能丰富的库,该库必须是通用的,而与我们的简单C代码完全可以满足我们的需求,仅此而已。但是,部分原因是由于.NET框架的模块化,面向对象的性质使自己能够执行很多重复执行,而这通常可以通过过程方法来避免。
我不是在尝试使用C#或.NET框架。我也不是说模块化,泛化,库/语言功能,OOP等都是不好的事情。我曾经在C,后来的C ++和最近的C#中完成大部分开发工作。同样,在使用C之前,我主要使用汇编语言。随着我的语言“一步一步”发展,我可以在更短的时间内编写出更好,更可维护,更强大的程序。但是,它们的执行速度往往会慢一些。
我认为没有人提到C编译器比Java编译器付出了更多的努力这一事实。
由于已经说明的许多原因,C可以进行极度优化-比几乎任何其他语言都多。因此,如果其他语言编译器投入相同的精力,C可能仍然会排在首位。
我认为至少有一种候选语言可以比C更好地进行优化,因此我们可以看到产生更快二进制文件的实现。我之所以想到数字火星D,是因为创建者非常谨慎地构建了一种可能比C更好地优化的语言。可能还有其他语言也有这种可能性。但是我无法想象,任何一种语言的编译器都将比最好的C编译器快百分之几。我想错了。
我认为真正的“垂头丧气的果实”将使用旨在方便人类优化的语言。熟练的程序员可以使任何语言的运行速度更快-但有时您必须做一些荒谬的事情或使用不自然的结构来实现这一目标。尽管会一直努力,但是一种好的语言应该产生相对快速的代码,而不必沉迷于程序的确切编写方式。
同样重要的是(至少对我而言),最坏情况的代码往往很快。Web上有许多“证明”,证明Java比C快或快,但这是基于“摘樱桃”的例子。我不是C的忠实拥护者,但我知道我用C编写的所有内容都将运行良好。使用Java,它将“大概”以15%的速度运行,通常在25%的速度内运行,但是在某些情况下,运行速度可能会更差。在任何情况下,它的速度一样快或在百分之几之内通常是由于大部分时间都花在了经过大量优化的C语言的库代码中。
这实际上是一种永久的虚假。虽然确实C语言程序通常会更快,但并非总是如此,特别是如果C程序员不太擅长于此。
人们往往会忘记的一个明显的大漏洞是程序必须阻止某种类型的IO,例如任何GUI程序中的用户输入。在这些情况下,使用哪种语言并不重要,因为您受到输入数据的速度的限制,而不是处理数据的速度限制。在这种情况下,使用C,Java,C#甚至Perl都没关系。您只是走得比数据输入快得多。
另一个主要问题是,使用垃圾回收而不使用适当的指针可使虚拟机进行许多其他语言无法提供的优化。例如,JVM能够在堆上移动对象以对其进行碎片整理。由于下一个索引可以简单地使用而不是在表中查找,因此这使得将来的分配要快得多。现代的JVM也不必实际释放内存。取而代之的是,它们只是在GC时移动活动对象,而从死对象中耗尽的内存基本上是免费恢复的。
这也带来了有关C的有趣观点,甚至在C ++中也是如此。一种设计理念是“如果不需要它,就不用付钱”。问题是,如果您确实想要它,您最终将为此付出代价。例如,Java中的vtable实现往往比C ++实现要好得多,因此虚拟函数调用要快得多。另一方面,您别无选择,只能在Java中使用虚拟函数,它们仍然会花费一些钱,但是在使用大量虚拟函数的程序中,降低的成本加起来了。
与其说语言,不如说是工具和库。C可用的库和编译器比新语言要老得多。您可能会认为这会使它们变慢,但很不利。
这些库是在处理能力和内存非常宝贵的时候编写的。为了工作,必须非常高效地编写它们。C编译器的开发人员也有很长时间从事针对不同处理器的各种聪明的优化工作。C的成熟度和广泛采用使其比同年龄的其他语言有明显的优势。与较不强调原始性能的新型工具相比,它也使C具有速度优势。
惊奇地看到旧的“ C / C ++ 必须比Java更快,因为Java被解释了”的神话仍然存在。有几年的文章以及最近的文章用概念或度量解释了为什么并非总是这样的原因。
当前的虚拟机实现(顺便说一句,不仅仅是JVM)可以利用程序执行过程中收集的信息,通过多种技术动态地调整代码的运行状态:
以及其他各种调整,以了解代码实际在做什么以及运行代码的环境的实际特征为基础。
不要用别人的话来理解,而是在代码的任何性能关键部分中都使用C语言和您选择的语言进行反汇编。我认为您只需在运行时在Visual Studio中的反汇编窗口中查看反汇编的.Net。如果使用windbg对于Java来说比较棘手,应该可以,尽管如果使用.Net进行操作,则许多问题都是相同的。
我不想在不需要的情况下用C编写代码,但是我认为这些答案中的许多主张都可以通过简单地在C和C语言中分解相同的例程来抛弃C以外的语言的速度。使用您选择的高级语言,尤其是在涉及大量数据的情况下(如性能关键型应用程序中常见的情况)。不知道,Fortran在其专业领域可能是个例外。它比C高吗?
我第一次将JITed代码与本机代码进行了比较,从而解决了.NET代码是否可以与C代码相比运行的所有问题。额外的抽象级别和所有安全检查会带来巨大的成本。同样的成本可能适用于Java,但不要相信我,而是在性能至关重要的方面尝试使用。(任何人都对JITed Java足够了解,可以在内存中找到已编译的过程吗?这肯定有可能)
1)正如其他人所说,C为您做的更少。没有初始化变量,没有数组边界检查,没有内存管理等。其他语言中的这些功能消耗了C不会花费的内存和CPU周期。
2)回答说,C的抽象程度较低,因此速度较快,我认为只有一半正确。从技术上讲,如果您有一个用于语言X的“足够高级的编译器”,那么语言X可以达到或等于C的速度。与C的不同之处在于,由于C的映射非常明显(如果您学习过架构课程),并且直接使用汇编语言,即使是天真的编译器也可以做得不错。对于像Python这样的东西,您需要一个非常高级的编译器来预测对象的可能类型并动态生成机器代码-C的语义非常简单,因此简单的编译器就可以很好地完成工作。
在过去的美好时光中,只有两种类型的语言:编译和解释。
编译语言利用“编译器”读取语言语法并将其转换为相同的汇编语言代码,而不仅仅是直接在CPU上。解释的语言使用了两种不同的方案,但实际上语言语法已转换为中间形式,然后在“解释器”(用于执行代码的环境)中运行。
因此,从某种意义上说,在代码和机器之间还有另一个“层”(解释器)。而且,像在计算机中一样,更多意味着更多的资源被使用。口译员比较慢,因为他们必须执行更多操作。
最近,我们看到了更多的混合语言,例如Java,它们同时使用编译器和解释器来使它们工作。它很复杂,但是JVM比旧的解释器更快,更复杂,更优化,因此(随着时间的推移)它的性能变化要好得多,接近于直接编译的代码。当然,较新的编译器还具有更多出色的优化技巧,因此它们倾向于生成比以前更好的代码。但是大多数优化通常会(尽管并非总是)进行某种权衡取舍,因此并非在所有情况下都总是较快。像其他所有东西一样,没有什么是免费的,因此优化器必须从某个地方夸耀自己(尽管经常使用编译时CPU来节省运行时CPU)。
回到C,这是一种简单的语言,可以将其编译为相当优化的程序集,然后直接在目标计算机上运行。在C语言中,如果增加一个整数,很有可能只是CPU中的一个汇编程序步骤,但是在Java语言中,它最终可能会比这更多(并且还可能包含一些垃圾回收: -)C为您提供了一个更接近机器的抽象(汇编程序是最接近的),但是您最终不得不做更多的工作才能使它运行,并且它没有那么受保护,易于使用或对错误友好。大多数其他语言为您提供了更高的抽象度,并为您提供了更多的底层细节,但是作为其高级功能的交换,它们需要更多的资源来运行。当您概括一些解决方案时,您必须处理更广泛的计算,
保罗
++i
可能会编译为“加[ebp-8],1”。并不是说获取,递增,存储仍然没有发生,但这是由CPU处理的,就像Paul所说的,这只是一条指令。
抛开诸如热点优化,预编译的元算法和各种形式的并行性之类的高级优化技术,语言的基本速度与支持操作通常所需的隐式幕后复杂性密切相关。在内部循环中指定。
也许最明显的是对间接内存引用的有效性检查-例如检查指针是否存在null
以及是否针对数组边界检查索引。大多数高级语言都隐式执行这些检查,而C则不。但是,这不一定是这些其他语言的基本限制 -足够聪明的编译器可能能够通过某种形式的循环不变代码运动从算法的内部循环中删除这些检查。
C(以及类似程度的密切相关的C ++)的更根本优势是严重依赖基于堆栈的内存分配,该内存本质上可以快速进行分配,释放和访问。在C(和C ++)中,主调用堆栈可用于分配基元,数组和聚合(struct
/ class
)。
虽然C确实提供了动态分配任意大小和寿命的内存的功能(使用所谓的“堆”),但是默认情况下会避免这样做(改为使用堆栈)。
令人着迷的是,有时可以在其他编程语言的运行时环境中复制C内存分配策略。asm.js证明了这一点,它允许将用C或C ++编写的代码转换为JavaScript的子集,并可以在Web浏览器环境中安全地运行-速度接近自然。
顺便说一句,C和C ++在速度方面胜过大多数其他语言的另一个领域是与本地机器指令集无缝集成的能力。一个明显的例子是(依赖于编译器和平台)SIMD内部函数的可用性,这些内部函数支持构建自定义算法,该算法利用现在几乎无处不在的并行处理硬件-同时仍利用该语言提供的数据分配抽象(下)级别的寄存器分配由编译器管理)。
我在链接上找到了关于为什么某些语言更快而有些慢的链接的答案,我希望这会更清楚地说明为什么C或C ++比其他语言快。还有其他一些语言也比C快,但是我们不能使用所有这些。一些解释-
Fortran仍然很重要的主要原因之一是因为它速度快:用Fortran编写的数字运算例程比用大多数其他语言编写的等效例程要快。之所以使用与Fortran在此领域竞争的语言(C和C ++)是因为它们在性能方面具有竞争力。
这就提出了一个问题:为什么?C ++和Fortran使它们快速运行的原因是什么?为什么它们比其他流行的语言(如Java或Python)好?
解释与编译根据编程语言和所提供功能的不同,可以使用多种方法对编程语言进行分类和定义。在查看性能时,最大的区别是解释语言和编译语言之间的区别。
鸿沟并不难;而是有一个频谱。一方面,我们有传统的编译语言,其中包括Fortran,C和C ++。在这些语言中,存在一个离散的编译阶段,该阶段将程序的源代码转换为处理器可以使用的可执行形式。
此编译过程包含几个步骤。源代码经过分析和解析。此时可以检测到基本的编码错误,如错别字和拼写错误。解析的代码用于生成内存中的表示形式,该表示形式也可以用于检测错误-这次是语义错误,例如调用不存在的函数,或者尝试对文本字符串执行算术运算。
然后,此内存中表示形式用于驱动代码生成器,该代码生成器生成可执行代码。在此过程中的不同时间执行代码优化,以提高生成的代码的性能:可以对代码表示形式执行高级优化,而对代码生成器的输出使用较低级别的优化。
实际执行代码会在稍后发生。整个编译过程仅用于创建可以执行的内容。
在另一端,我们有口译员。解释器将包括一个类似于编译器的解析阶段,但是该解析阶段用于驱动直接执行,并立即运行程序。
最简单的解释器中包含与语言支持的各种功能相对应的可执行代码,因此它将具有添加数字,连接字符串的功能,以及给定语言所具有的其他功能。在解析代码时,它将查找并执行相应的函数。在程序中创建的变量将保留在某种查找表中,该表将其名称映射到其数据。
解释器样式的最极端示例是诸如批处理文件或Shell脚本之类的东西。在这些语言中,可执行代码通常甚至不内置在解释器本身中,而是独立的独立程序。
那么,为什么这会影响性能呢?通常,间接的每一层都会降低性能。例如,将两个数字相加的最快方法是将这两个数字都放在处理器的寄存器中,并使用处理器的加法指令。那就是编译程序可以做的;他们可以将变量放入寄存器中并利用处理器指令。但是在解释程序中,相同的加法可能需要在变量表中进行两次查找以获取要添加的值,然后调用一个函数来执行加法。该函数很可能使用与编译程序用来执行实际加法的处理器指令相同的处理器指令,但是实际上可以使用该指令之前的所有额外工作会使事情变慢。
如果您想了解更多信息,请检查来源
某些C ++算法比C快,而其他语言中算法或设计模式的某些实现可能比C快。
当人们说C很快,然后再谈论其他语言时,他们通常以C的性能为基准。
使用现代的优化编译器,纯C程序几乎不可能比已编译的.net代码快得多。随着生产力的提高,像.NET框架提供的开发者,你可以做的事情在一天以前需要数周或数月再加上相比,开发人员的薪水硬件成本低廉定期下,它只是WAY便宜写用高级语言填充内容,并以任何慢速投放硬件。
Jeff和Joel之所以说C是“真正的程序员”语言,是因为C中没有人手。您必须分配自己的内存,释放该内存,进行自己的边界检查等。作为new object(); 没有垃圾收集,类,OOP,实体框架,LINQ,属性,属性,字段或类似的东西。您必须了解指针算术以及如何取消对指针的引用之类的知识。并且,就此而言,知道并理解什么是指针。您必须知道什么是堆栈帧以及什么是指令指针。您必须了解正在使用的CPU体系结构的内存模型。对微型计算机的架构有很多隐含的理解(通常是使用C#或Java进行编程的C语言中根本不存在,也没有必要。所有这些信息已被卸载给编译器(或VM)编程器。
自动和手动之间是有区别的,高级语言是抽象的,因此是自动化的。C / C ++是手动控制和处理的,即使错误检查代码有时也需要人工。
C和C ++也是已编译的语言,这意味着它们都不在任何地方运行,这些语言必须针对您使用的硬件进行微调,从而增加了额外的陷阱。尽管随着C / C ++编译器在所有平台上变得越来越普遍,这种情况现在已逐渐消失。您可以在平台之间进行交叉编译。仍然不是到处运行的情况,您基本上是在指示编译器A针对编译器B编译相同代码,不同体系结构。
底线C语言并不是要易于理解或推理,这也是为什么将其称为系统语言。他们出现在所有这些高级抽象废话之前。这也是为什么它们不用于前端Web编程的原因。他们只是不适合这项任务,他们的意思是解决常规语言工具无法解决的复杂问题。
这就是为什么您会得到疯狂的东西(例如微体系结构,驱动程序,量子物理学,AAA游戏,操作系统)之类的东西的原因,而C和C ++恰好适合这些东西。速度和数字紧缩是主要领域。
原因有很多,包括: