控制台应用程序比GUI应用程序运行得更快吗?

16

我对编程的世界比较陌生。我有几个性能方面的问题:

  1. 控制台应用程序是否比带图形用户界面的应用程序运行更快?

  2. 像C和Pascal这样的语言是否比面向对象的语言,如C++和Delphi更快?我知道语言速度更多取决于编译器而不是语言本身,但是过程式语言的编译器是否会生成比面向对象语言更快的代码(包括可以生成C代码的C++编译器)?


16
代码速度更多地取决于代码的质量,而不是它所编写的语言。使用你能够编写优秀代码的语言进行工作,速度将成为一个附带的好处 - 不要只因为某种语言据说很快就使用它,如果你不能在该语言中编写出优秀的代码,那么它仍然会很慢。 - Amber
你应该把你的问题分成两个,因为(除了“更快”的部分之外),它们是没有关联的。 - Jeroen Wiert Pluimers
@Dav:一些项目实际上需要依赖于语言的性能...Omair可能不会写下一个地震引擎,但为什么要假设语言性能对任何人都不重要呢? - Inverse
1
@Inverse:我的评论更多的是想说“不要使用你无法写出高质量代码的编程语言”,而不是“使用你能够写出高质量代码的任何编程语言”——在某些情况下,编程语言选择仍然很重要,但是在任何你写出低质量代码的编程语言中,程序都会变得缓慢。 - Amber
9个回答

31

控制台应用程序比基于 Windows 的应用程序快吗?

简短回答:不是的
长篇回答:

在控制台应用程序中,没有GUI线程需要重新绘制窗口和接受用户输入,因此从这个意义上讲,控制台应用程序可能会稍微快一些(因为它少了一个线程抢占CPU周期)。但是,由于现代操作系统同时运行多个进程,因此控制台应用程序仍然会与系统中的其他进程竞争CPU,所以不会更快。

类似C和Pascal这样的语言是否比面向对象的语言如C++和Delphi更快?

简短回答:不是的
长篇回答:

在等效的程序中,C和C++的性能大致相同。尽管编程语言确实可以影响性能,但通常你需要关注的主要是算法(您的应用程序逻辑表达的内容)而不是算法所编写的语言。


实际上,在基于控制台的应用程序中,GUI线程只是对您隐藏了。但是像素仍然需要绘制到屏幕上,并且控制台窗口可以拖动,因此显然输入会以某种方式处理。 - MSalters
1
@MSalters,控制台应用程序也可以在后台运行,并重定向I/O,这种情况下将没有GUI线程。虽然,是的,如果有控制台窗口,则需要重新绘制和接受I/O。 - Michael Aaron Safyan
2
快速而简单的评论:Delphi对象代码比Delphi过程代码稍慢一些,这是因为有一个"self"指针(必须存储在CPU寄存器或堆栈中),并且如果使用多个函数重写,速度会变慢。当您查看Delphi生成的代码时(CPU视图,CTRL-ALT-C),您可以看到这一点。C++也是如此:如果使用对象代码而不是过程代码(像普通的C语言),它会有更多的开销,因为涉及到对象继承等。对于嵌入式软件,有时必须使用C语言,因为C++太慢或者开销太大。 - André
7
安德烈·穆舍(André Mussche):是的,支持对象需要一些额外开销。但是,如果这些对象能够带来更好的设计,整个应用程序可能会更快。例如,虚函数调用比反复测试 if else if 阶梯要快得多。 - Billy ONeal
2
@Andre,在“等效程序”(例如可重入程序)中,仍然需要传递指向包含与该调用相关的数据的结构体的指针...只是不会自动进行。例如,在pthread库中的调用中...您仍然需要传递“pthread_t”对象,它只是显式的,因此我认为您的说法是不准确的。如果使用共享状态,则不再等效(除非在OOP版本中使用静态函数,但那样就没有“this”指针了)。 - Michael Aaron Safyan

5
Michael Aaron Safyan已经给出了一个非常好的答案。我想在为什么面向对象语言有时会与较慢的代码相关联方面做出一点贡献。
现实世界对我们程序员的要求不断迫使我们在更短的时间内编写更多的代码。即使是非常熟练的程序员,汇编语言也会赢得每个速度记录,因为程序员编写的恰好是机器需要执行的操作,几乎没有其他内容。在实践中,大多数编程不是用汇编语言完成的,因为它太繁琐、容易出错。编译语言让程序员更加高效,因为它们让编译器处理大部分详细工作。
向同样的方向前进,Delphi使用自动字符串:无论何时使用它们,它们的长度都是“正确”的;如果你连接两个字符串,就会产生一个新的字符串,它的长度适合以前的字符串组合。如果你改变了那个字符串并使它更长,就会创建一个新的字符串,以前的字符串会被自动丢弃。作为C程序员,你可以预先确定程序将要做什么,并为更大的字符串分配足够的空间,这样你就不必创建一个新的字符串并丢弃旧的字符串。因此,字符串的内存管理是为了方便程序员,以一些CPU时间为代价。
同样,面向对象允许你将相关数据组作为同质块处理,而不是字符串和数字。有时候并不需要所有这些信息,在低级别的C程序中,你可能会省略一些对象所需的操作和内存使用。这又一次是程序员方便性与CPU速度之间的权衡。
最后,一些接口被认为非常复杂,软件公司试图通过创建概念上更简单的面向对象框架来使它们变得可行。你可以创建一个窗口对象,而不是调用打开窗口的函数,通常会带来一些开销。在一个奇怪的发展中,软件公司和个人开发者经常构建更进一步的面向对象框架来隐藏或处理其他框架的复杂性。一些旧项目最终在原始功能的顶部拥有多层面向对象框架,毫不奇怪,它们花费大量时间管理自己,同时表现出对客户的较差性能,同时消耗大量内存。
总之,面向对象的代码有时会因为它的使用方式而与较差的性能相关联;但特别是在C++的情况下,语言本身并没有直接导致它“慢”。

@Carl,谢谢你的赞美...不过,我认为你关于汇编语言的说法是不正确的;除了汇编优化大师外,由编译器生成的汇编代码几乎总是比手写的汇编代码更快。 - Michael Aaron Safyan
@Michael:是的,我认为我们基本上是同意的。这就是我的“假设有非常熟练的程序员”的意思。 - Carl Smotricz

4

正如已经提到的,你的代码通常在控制台应用程序中运行速度与在GUI应用程序中运行速度相同。

真正的区别在于开销。所有其他条件相等的情况下,GUI应用程序是更大的EXE文件,启动和关闭需要更多时间,并且会消耗更多资源。在应用程序运行时更新UI也是很好的形式,但这可能会从CPU密集任务中占用一些周期。

但在大多数情况下,这不应该有影响。


2
由于缺少消息映射、窗口事件、GUI线程等,控制台应用程序可能看起来比基于窗口的应用程序更快。但是,在控制台应用程序和基于窗口的应用程序之间进行选择时,速度不应该是唯一的标准。正如您所知,窗口应用程序是“事件驱动编程”。
关于语言速度,我不能说只有c编译器会生成更快的执行代码。实际上,c++编译器会对编译后的代码进行大量优化,以最大化其速度。此外,面向对象的模型非常适合编程、维护和扩展特性。
因此,根据需求使用适当的语言和技术。

2
“显然”?请详细说明... - Jeroen Wiert Pluimers
抱歉显得很明显。我编辑了我的答案。 - Akaanthan Ccoder

1

由同一编译器生成的相同代码无论是在GUI应用程序还是控制台中运行,都将以相同的速度运行。此外,编译为C++的C代码(假设它也符合C++标准)与编译为C的相同代码不会有显著差异,如果有的话。

然而,操作系统方面可能会影响性能,控制台应用程序除非被阻塞在操作系统或I/O调用上,否则将消耗其整个时间片;GUI应用程序通常是事件驱动的,因此等待事件处理它,然后等待下一个事件;虽然您可能有类似于控制台应用程序的工作线程。此外,GUI应用程序必须花费时间更新其更复杂的显示。但这些方面受应用程序设计者和操作系统控制,而不是编译器。

就面向对象编程而言,它本质上并不慢,但有些结构和架构可以导致更快的应用程序开发、更好的可维护性和鲁棒性,但这可能会牺牲一些性能。


1

不是的,甚至相反可能更快:

正如Dav在他的评论中所说,代码决定了你的应用程序有多快。这也适用于编译器的另一面,即生成的机器代码。

通常情况下,较新的编译器会产生更快的机器代码,因为它们利用了先进的CPU功能,并执行现代编译器优化,这些优化在早期的编译器中找不到。

例如,可以创建一个Pascal应用程序,如果使用Delphi编译而不是旧的Turbo Pascal编译器,则运行速度更快。

简而言之:不要仅仅因为它们看起来更轻巧就使用旧的/原始的编译器。在大多数情况下,您不会获得任何性能提升。


面向对象的代码比过程式代码慢,因为它需要额外(但很小)的开销来处理对象继承、函数重写等。 - André

0
关于你的第二个问题,我想回应Michael和Carl,并增加另一个考虑因素 - 即自然厌恶真空,这也适用于源代码。
由于高级语言允许使用更少的代码完成相同的工作,它们也允许使用相同的代码完成更多的工作,即使这并不需要。
例如,有时你会在SO上看到这样的问题:
time starttime = now;
for (i = 0; i < 1000000; i++){
  cout << i;
}
cout << (now - starttime);

并询问是否这次循环开销,隐含地假设由于<<只有两个字符,因此可以忽略不计。实际上,循环内部的<<比循环本身需要更多的周期。根据我的经验,几乎所有程序员都会以各种方式这样做,包括我自己,他们感激用如此少的代码就能完成如此多的工作,所以他们经常这样做,并且认为如果他们这样做了,那么就是必要的。

因此,语言的级别越高,性能调优的技能就越重要


0

这仅适用于您的第一个问题:

当控制台应用程序在图形环境中交互运行(例如GNOME桌面或Windows上),它们会在终端窗口中运行,该窗口实际上是一个GUI应用程序。因此,任何GUI成本(例如必须运行消息循环,不必分配GUI小部件等)都只是转移到托管环境。全屏运行控制台应用程序(text mode屏幕)确实减少了CPU和视频卡之间的通信,但任何速度提升都将是微不足道的。

然而,相比图形输出,控制台UI更容易开发,代价是灵活性较差。只需比较使用ncurses创建表单所需的工作量与使用GTK所需的工作量即可。


0

感谢各位帮我解决了这个问题, 但我还是感到困惑。我的印象是,面向对象的语言性能开销比较大,因为它们的库过于庞大。如果你使用 Blitz++ 库在 C++ 中编写程序,它将比 C 运行得更快,或者与 C 相同,但是普通的 C++ 库使得 C++ 比 C 更慢。同样适用于 Pascal 和 Delphi,如果您使用 Delphi7 而不是 Delphi 2010 来编译程序,它将运行得更快,因为 Delphi 2010 的单元比较重(警告:我没有比较过 Delphi 7 和 2010,也没有比较过 C++ 和 C,这只是我通过在线论坛阅读和语言之间的争论形成的印象)。你们可能会认为我有点疯狂,但我更喜欢一个程序(即使只是文本编辑器)完美无缺地运行,即使我的程序要在超级计算机上运行,我仍然喜欢尽可能地优化我的代码。也许我有强迫症?


使用Delphi 2010编译的程序很可能比使用Delphi 7编译的程序更快。自那时以来,内存管理器已经发生了变化,Delphi 2010生成了更优化的代码(是否使用了FastCode代码?)。关于臃肿的库:大型库可能需要稍微多一点时间来加载,但执行速度主要受到实现(使用的算法)和可能的“功能丰富性”的影响。所以如果库A比库B更快,那么A的编码更好或者包含的功能比B少,但这与面向对象与过程化无关。 - The_Fox
“特性丰富性”如何会导致库变慢?我不理解,请说明。 - Omair Iqbal
1
看一下TList的实现。在旧时代(Delphi 5之前),当你清空一个TList时,它只是将其内部计数器设置为零并释放为指针列表分配的内存。随着从TList派生出来的TObjectList的出现,每次删除项目时需要被通知。因此,现在清空一个TList时,它将为列表中的每个项目调用Delete,这又会调用Notify。清空TList现在是一个O(n)操作,而以前是一个O(1)操作。因此,为了实现TObjectList拥有对象的特性,另一种方法变得更慢了。 - The_Fox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接