C代码是否运行更快?

9

在Objective-C中调用C代码会带来性能上的提升吗?

我曾经读到过消息传递相对于其他使用函数调用的语言来说更慢。如果我从Objective-C代码中调用C函数,是否可以避免消息传递的开销呢?

在优化性能时,建议编写最关键的函数和过程以C代码形式而不是使用Objective-C对象吗?

编辑:
鉴于许多答案都警告了有关过早进行优化和代码可读性的问题,我想澄清一下,我并没有考虑常规应用程序,而是非常具体的应用,例如:

  • 图形处理
  • 加密或压缩算法。
  • 数学计算

总的来说,这些函数或过程不需要面向对象设计,并且旨在多次使用参数被调用。

5个回答

11

很不可能你正在编写已经进行了优化的代码,以至于消息发送成为瓶颈。按照对你自己来说最合理的方式编写代码,然后使用Instruments进行分析和优化如果有必要。几乎可以确定,如果你的代码有任何缓慢之处,那肯定是由于比消息发送更高级别的问题造成的。


OpenGL ES 是用 C 编写的,对吧?这是我所说的那种代码的一个很好的例子。 - Mister Smith
过早优化是万恶之源。 - Manlio
OpenGL传统上是用C语言编写的,但是许多面向对象的语言都有包装器,包括Objective-C,它们的表现非常出色。这更多地取决于您想让代码看起来像什么,而不是您希望它运行得有多快。 - andyvn22
1
对于许多应用程序类型来说,早期智能优化应用程序的算法和数据类型是必要的,以获得接近可用的实时响应或帧速率。 - hotpaw2
3
尽管避免过早优化的原则是正确的,但在实际产品中存在许多情况需要处理消息传递,因为这会带来显著的开销。不应在被调用数千次或更多次的紧密循环中频繁使用消息传递。与方法不同,小型函数可以内联,有时会带来显著的性能提升(特别是当编译器可以应用二级优化时)。您是正确的,不应该过早进行优化,但这并不意味着不考虑消息传递不常见。 - Rob Napier

8

这是一个基准测试,比较了消息传递和调用C函数。以下是调用不同实现的斐波那契函数约14亿次的结果。

Message Passing 23.495 seconds
IMP Calling     16.033 seconds
C Function      9.709 seconds

是的,在调用Objective C方法时会有一些开销。但除非在某些情况下,这不会影响您的应用程序性能。事实上,消息传递仍然比大多数其他操作(如浮点除法)更有效率。

此外,大多数应用程序花费的时间都是等待用户输入、下载数据等。


谢谢,我正准备自己做基准测试。我知道一开始就不应该采取这种方法。我在考虑那些被多次调用且有多个参数的函数,例如光线追踪或重量级加密算法。所以这是有意义的。 - Mister Smith
1
最后,我自己做了一个基准测试,也使用了递归斐波那契数列(但不是链接中显示的代码)。在 Objective-C 中,即使使用 C 类型(long、int),速度也比 C 函数慢 2.35 倍。显然,在 C 中编写某些东西是值得考虑的。 - Mister Smith

4
建议在性能关键的内部循环中使用精心编写的纯C代码,而不是使用Objective C。例如,在实时音频信号处理或图像处理代码中,使用对象数据类型或消息很少有任何好处。当涉及数千个单独的音频样本或每帧时间的百万像素时,所有不需要的方法调度周期只会浪费用户的电池寿命。其他类型的复杂数值模拟和有限元模型(等等)也可能从保持内部循环简单以获得编译器优化的最佳结果中受益。
然而,只需要按人类步伐偶尔发生的高级操作可能不会消耗足够的消息传递开销以进行测量。因此,在这里改善代码可读性和重用的任何抽象都不太可能为用户带来任何性能或电池寿命的损失。

1

运行时解释初始消息,因此比C++虚拟方法调用慢大约三倍(C++虚拟方法调用本身略慢于直接调用)。然而,后续的调用会被IMP缓存,在大多数实现中比C++虚拟方法调用更快,但仍然略慢于C或C++的直接函数调用。

因此,是的,可能会有性能提升,但在放弃Objective-C所有优势之前,您应该确保“优化”的好处是显著的。在大多数情况下,可以通过使用合适的数据结构和算法等方式获得更大的性能优势。大多数代码在执行任务时花费时间比在函数调用开销上 - 结果可能会有所不同。

参见Objective C消息派发机制


1

直接调用C函数总是比调用Obj-C方法更快;但是,正如许多人指出的那样,在性能敏感的代码之外,它不太可能成为瓶颈。

然而,你可以反过来问,如果它更慢,为什么要使用方法?-反对“过早优化”的法令并不意味着“故意编写糟糕的代码”。

这是一个平衡,方法和函数之间的界限模糊,你必须做出选择。以下两个端点可能有所帮助:

  1. 如果代码将改变对象的状态-使用方法。
  2. 如果代码是自然函数;接受一些输入,产生一个输出,不操作状态(具有“副作用”);那么函数是有意义的。

对于所有中间点,请根据自己的判断使用。

例如,如果您在一个类中有一段代码需要在多个位置计算金字塔的体积,您可以将体积算法抽象出来:方法还是函数?函数 - 它接受一些值,产生一个值,不改变对象状态。甚至更好的方法是将其作为static函数,这样就可以将其有效地设置为类的私有函数,并且不会污染应用程序的命名空间。如果只在类内部需要该算法,则将其编写为方法没有任何好处 - 我认为这是“糟糕的代码”(但这是一种观点!)

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