了解汇编程序的原因之一是,有时可以使用汇编程序来编写比用高级语言(特别是C语言)编写的代码性能更好的代码。然而,我也听人说过很多次,尽管这并非完全错误,但实际上可以使用汇编程序来生成性能更好的代码的情况极其罕见,并且需要汇编方面的专业知识和经验。

这个问题甚至没有涉及到这样一个事实,即汇编程序指令将是特定于机器的、不可移植的,或者汇编程序的任何其他方面。当然,除了这一点之外,了解汇编还有很多很好的理由,但这是一个需要示例和数据的具体问题,而不是关于汇编程序与高级语言的扩展论述。

谁能提供一些具体的例子,说明使用现代编译器汇编代码比编写良好的C代码更快,并且您能否用分析证据支持这一说法?我相信这些案例确实存在,但我真的很想知道这些案例到底有多深奥,因为这似乎是一个有争议的问题。


当前回答

这完全取决于你的工作量。

对于日常操作,C和c++已经很好了,但是有一些特定的工作负载(任何涉及视频的转换(压缩、解压缩、图像效果等))几乎需要组装才能达到性能。

它们通常还涉及使用特定于CPU的芯片组扩展(MME/MMX/SSE/等等),这些扩展是为这些类型的操作而优化的。

其他回答

这个问题有点毫无意义,因为无论如何c都是编译到汇编程序的。 但是,通过优化编译器生成的汇编程序几乎是完全优化的,所以除非你在优化特定的汇编程序方面做了20个博士学位,否则你无法打败编译器。

不需要给出任何具体的示例或分析器证据,当您比编译器知道的更多时,您可以编写比编译器更好的汇编程序。

In the general case, a modern C compiler knows much more about how to optimize the code in question: it knows how the processor pipeline works, it can try to reorder instructions quicker than a human can, and so on - it's basically the same as a computer being as good as or better than the best human player for boardgames, etc. simply because it can make searches within the problem space faster than most humans. Although you theoretically can perform as well as the computer in a specific case, you certainly can't do it at the same speed, making it infeasible for more than a few cases (i.e. the compiler will most certainly outperform you if you try to write more than a few routines in assembler).

另一方面,有些情况下编译器没有那么多的信息——我想说主要是在使用不同形式的外部硬件时,编译器不知道这些信息。主要的例子可能是设备驱动程序,其中汇编程序结合人类对相关硬件的熟悉知识可以产生比C编译器更好的结果。

其他人提到了特殊用途指令,这就是我在上面一段中所说的——编译器可能对这些指令了解有限或根本不了解,这使得人类可以编写更快的代码。

简短的回答吗?有时。

从技术上讲,每一个抽象都有成本,而编程语言是CPU如何工作的抽象。然而C非常接近。几年前,我记得当我登录UNIX帐户并收到以下财富信息时(当时这种东西很流行),我笑出声来:

C程序设计语言——A 语言结合了 汇编语言的灵活性 汇编语言的强大。

这很有趣,因为这是真的:C就像可移植的汇编语言。

值得注意的是,汇编语言无论如何编写都可以运行。然而,在C语言和它生成的汇编语言之间有一个编译器,这是非常重要的,因为你的C代码有多快与你的编译器有多好有很大关系。

当gcc出现时,它如此受欢迎的原因之一是它通常比许多商业UNIX版本附带的C编译器要好得多。它不仅是ANSI C(没有任何K&R C的垃圾),更健壮,通常能产生更好(更快)的代码。不是总是,而是经常。

我告诉你这一切是因为没有关于C和汇编器速度的统一规则,因为C没有客观的标准。

同样地,汇编程序也会根据你正在运行的处理器、你的系统规格、你正在使用的指令集等而有很大的不同。历史上有两个CPU体系结构家族:CISC和RISC。CISC中最大的玩家过去是,现在仍然是Intel x86架构(和指令集)。RISC主宰了UNIX世界(MIPS6000、Alpha、Sparc等等)。CISC赢得了民心之战。

不管怎样,当我还是一个年轻的开发人员时,流行的观点是,手写的x86通常比C快得多,因为架构的工作方式,它的复杂性受益于人类的操作。另一方面,RISC似乎是为编译器设计的,所以没有人(我知道)写Sparc汇编器。我相信这样的人确实存在,但毫无疑问,他们现在都疯了,被送进了精神病院。

指令集是一个重要的点,即使在同一家族的处理器。某些英特尔处理器具有SSE到SSE4等扩展。AMD有他们自己的SIMD指令。像C这样的编程语言的好处是,人们可以编写他们的库,以便对您运行的任何处理器进行优化。这在汇编程序中是一项艰苦的工作。

你仍然可以在汇编程序中做一些编译器无法做的优化,一个编写良好的汇编程序算法将会和它的C等效程序一样快或更快。更大的问题是:这样做值得吗?

Ultimately though assembler was a product of its time and was more popular at a time when CPU cycles were expensive. Nowadays a CPU that costs $5-10 to manufacture (Intel Atom) can do pretty much anything anyone could want. The only real reason to write assembler these days is for low level things like some parts of an operating system (even so the vast majority of the Linux kernel is written in C), device drivers, possibly embedded devices (although C tends to dominate there too) and so on. Or just for kicks (which is somewhat masochistic).

第一点不是答案。 即使你从来没有用它编程,我发现至少知道一个汇编指令集是有用的。这是程序员永无止境的追求的一部分,他们想知道得更多,从而变得更好。当你进入一个没有源代码的框架时,它也很有用,至少对正在发生的事情有一个粗略的了解。它还可以帮助您理解JavaByteCode和. net IL,因为它们都类似于汇编程序。

To answer the question when you have a small amount of code or a large amount of time. Most useful for use in embedded chips, where low chip complexity and poor competition in compilers targeting these chips can tip the balance in favour of humans. Also for restricted devices you are often trading off code size/memory size/performance in a way that would be hard to instruct a compiler to do. e.g. I know this user action is not called often so I will have small code size and poor performance, but this other function that look similar is used every second so I will have a larger code size and faster performance. That is the sort of trade off a skilled assembly programmer can use.

我还想补充一点,这里有很多中间地带,您可以用C编译代码并检查生成的程序集,然后更改C代码或调整并作为程序集进行维护。

我的朋友从事微控制器的工作,目前是用于控制小型电动机的芯片。他在低级c和汇编的组合中工作。他曾经告诉我,有一天他在工作中把主循环从48条指令减少到43条。他还面临着各种选择,比如代码已经增长到填满256k芯片,业务需要一个新功能,你呢

删除现有功能 减少部分或全部现有特性的大小,可能会以性能为代价。 提倡改用成本更高、功耗更高、外形更大的更大芯片。

我想补充一点,作为一个商业开发人员,我有很多的投资组合或语言、平台、应用程序类型,我从来没有觉得有必要深入编写程序集。我一直都很感激我所学到的知识。有时会被调试进去。

我知道我已经回答了“为什么我要学习汇编器”这个问题,但我觉得这是一个更重要的问题,而不是什么时候更快。

所以让我们再试一次 你应该考虑组装

致力于底层操作系统功能 在编译器上工作。 工作在一个极其有限的芯片,嵌入式系统等

记住比较你的程序集和生成的编译器,看看哪个更快/更小/更好。

大卫。

以下是我个人经历中的几个例子:

Access to instructions that are not accessible from C. For instance, many architectures (like x86-64, IA-64, DEC Alpha, and 64-bit MIPS or PowerPC) support a 64 bit by 64 bit multiplication producing a 128 bit result. GCC recently added an extension providing access to such instructions, but before that assembly was required. And access to this instruction can make a huge difference on 64-bit CPUs when implementing something like RSA - sometimes as much as a factor of 4 improvement in performance. Access to CPU-specific flags. The one that has bitten me a lot is the carry flag; when doing a multiple-precision addition, if you don't have access to the CPU carry bit one must instead compare the result to see if it overflowed, which takes 3-5 more instructions per limb; and worse, which are quite serial in terms of data accesses, which kills performance on modern superscalar processors. When processing thousands of such integers in a row, being able to use addc is a huge win (there are superscalar issues with contention on the carry bit as well, but modern CPUs deal pretty well with it). SIMD. Even autovectorizing compilers can only do relatively simple cases, so if you want good SIMD performance it's unfortunately often necessary to write the code directly. Of course you can use intrinsics instead of assembly but once you're at the intrinsics level you're basically writing assembly anyway, just using the compiler as a register allocator and (nominally) instruction scheduler. (I tend to use intrinsics for SIMD simply because the compiler can generate the function prologues and whatnot for me so I can use the same code on Linux, OS X, and Windows without having to deal with ABI issues like function calling conventions, but other than that the SSE intrinsics really aren't very nice - the Altivec ones seem better though I don't have much experience with them). As examples of things a (current day) vectorizing compiler can't figure out, read about bitslicing AES or SIMD error correction - one could imagine a compiler that could analyze algorithms and generate such code, but it feels to me like such a smart compiler is at least 30 years away from existing (at best).

On the other hand, multicore machines and distributed systems have shifted many of the biggest performance wins in the other direction - get an extra 20% speedup writing your inner loops in assembly, or 300% by running them across multiple cores, or 10000% by running them across a cluster of machines. And of course high level optimizations (things like futures, memoization, etc) are often much easier to do in a higher level language like ML or Scala than C or asm, and often can provide a much bigger performance win. So, as always, there are tradeoffs to be made.