【问题标题】:Is weak typing a performance increase or a decrease?弱打字是性能提高还是降低?
【发布时间】:2012-03-27 15:35:12
【问题描述】:

在编写解释型语言时,弱类型和强类型哪个更快?

我想知道这一点,因为通常更快的动态类型解释语言(Lua、Javascript),事实上大多数解释语言都使用弱类型。

但另一方面,强类型提供了弱类型所不能保证的保证,那么,优化技术是否可以用于一种方法,而另一种方法则不可能?


对于强类型,我的意思是类型之间没有隐式转换。例如,这在强类型语言中是非法的,但在弱类型语言中(可能)是合法的:"5" * 2 == 10。尤其是 Javascript 因这些类型转换而臭名昭著。

【问题讨论】:

  • +1 一个有趣的问题,虽然我担心一般来说很难回答。我期待着关于解释器优化的血腥细节。
  • 明确一点,弱类型和强类型是什么意思? (我尽量避免对reasons given here 使用这些术语——人们以许多不兼容的方式使用它们。)
  • 强类型化,因为类型之间没有隐式转换。例如,这在强类型语言中是非法的,但在弱类型语言中(可能)是合法的:"5" * 2 == 10。特别是 Javascript 因这些类型转换而臭名昭著。编辑:将其添加到问题中。
  • 如今,大多数现代 JavaScript 引擎不再解释而是直接编译成字节码。所以很难把这个问题应用到那种语言上。
  • 这个问题真的没有意义,有两个方面。首先:执行这些隐式转换时会产生隐式转换的开销。不执行任何此类隐式转换的程序将是相同的,无论语言是否支持它们。所以你的问题就像问具有内置反正切函数的编程语言是否比没有的语言慢。其次:隐式转换的实现在动态类型语言和静态类型语言中是完全不同的;所以即使你的问题有连贯性

标签: optimization typing scripting-language


【解决方案1】:

在我看来,由于缺乏“强类型解释语言”(使用我从问题 cmets 中理解的定义),这个问题很难用明确的例子来回答。

我想不出任何可以解释且没有隐式转换的语言。我认为这有两个原因:

  1. 解释语言往往不是静态类型的。我认为这是因为如果您要实现静态类型语言,那么从历史上看,编译相对容易,并且会给您带来显着的性能优势。

  2. 如果一种语言不是静态类型的,那么它会被强制进行隐式转换。替代方案会让程序员的生活变得太难(他们必须跟踪类型,在源代码中不可见,以避免运行时错误)。

因此,在实践中,所有解释语言都是弱类型的。但是性能增加或减少的问题意味着与一些没有的比较。至少,如果我们想讨论不同的现有实施策略,它确实如此。

现在你可以回答“好吧,想象一下”。好的。因此,您要求在运行时检测到转换需要的代码与程序员明确添加转换的代码之间的性能差异。在这种情况下,您将比较动态检测转换需求与调用程序员指定的显式函数之间的区别。

从表面上看,检测总是会增加一些开销(在 [后期] 编译的语言中,可以通过 jit 改善,但您是在询问解释器)。但是如果你想要快速失败的行为(类型错误),那么即使是显式转换也必须检查类型。所以在实践中我想差异相对较小。

这又回到了原点——因为弱类型的性能成本很低(考虑到问题中的所有其他约束/假设),并且替代方案的可用性成本很高,大多数(全部?)解释语言支持隐式转换。

[对不起,如果我还是不明白。我担心我错过了一些东西,因为这个问题 - 以及这个答案 - 似乎并不有趣......]

[编辑:也许更好的方式来询问相同(?)的事情会是“动态(后期绑定?)语言处理类型转换的各种方式的比较优势/劣势是什么?”因为我认为您可能会争辩说 python 的方法特别强大(富有表现力),同时与其他解释语言具有相似的成本(并且这个问题避免了争论 python 或任何其他语言是否是“弱类型”)。 em>]

【讨论】:

  • 你肯定知道,Python 几乎没有隐式转换。数字类型被提升(以单向方式,并且总是从一种类型到更通用的类型),有人可能会隐含地争论if/and/or/not转换为布尔值(尽管也可以说所有对象都有一个真值,而这些对象只是获取该值并对其进行处理——and/or 返回其中一个操作数的事实支持这种观点)。除此之外,我现在知道任何隐式转换。我怀疑 Python 在这方面是唯一的。所以我敢挑战你的理由 #2。
  • 隐式转换是指隐式调用__float__ 等方法 - 请参阅docs.python.org/reference/datamodel.html#specialnames(所以__nonzero__ 是您所指的转换为布尔值)。
  • python 中一个非常常见的例子是转换为迭代器。这在惯用的 Python 代码中无处不在,并且以相同的方式实现 (__iter__iirc)。
  • __float__ 不是隐式调用的,它只是从floatAFAIK 调用的(也许在数字提升期间也是如此,但我们已经得到了那个)。 __iter__ 确实被隐式调用,但仅在 for 循环和 {list,dict,set} 理解的上下文中,因此它受到极大限制并且 总是 被调用。出于这个原因,我并不认为它是一种隐式转换。而且大多数“特殊方法”根本不转换 - 它们用于属性访问和运算符重载等目的。
  • __str__ 是另一种常见的。 iirc __float____add__ 的默认实现调用。更一般地说,我不确定你的意思是什么——是的,这些模糊了消息发送,所以你可以争辩说这不是隐式类型转换,而是方法调用。这很酷——这正是我说 python 有一个很好的解决方案时的意思,并且争论究竟什么是“弱类型”和不是“弱类型”在很大程度上是没有意义的。太没有意义了,我不会再做任何事情了。
【解决方案2】:

强类型是指类型之间没有隐式转换。

"5" * 2 == 10

问题在于“弱类型化”不是一个定义明确的术语,因为这种“隐式转换”有两种非常不同的方式发生,它们对性能的影响几乎相反:

  • “脚本语言方式”:值具有运行时类型,当操作需要不同类型时,该语言隐式应用语义规则在类型之间进行转换(例如将二进制数格式化为十进制字符串)。这往往会降低性能,因为它 A) 需要在运行时有类型信息,并且 b) 需要检查此信息。这两个要求都会带来开销。
  • “C 方式”:在运行时,它只是字节。如果您可以说服编译器在字符串上应用一个采用 4 字节整数的操作,那么根据您的操作方式,该字符串的前 4 个字节将被简单地视为它们是一个(可能非常大) 整数,否则会出现缓冲区溢出。或者恶魔从你的鼻子里飞出来。这种方法不需要任何开销,并且可以带来非常快的性能(以及非常严重的崩溃)。

【讨论】:

  • 实际上有三种方式,因为您省略了 C 方式:在编译时,表达式具有类型,并且可以插入隐式转换以根据需要将表达式从一种类型转换为另一种类型。例如,如果iint,那么5.0 * i 将隐式地将iint 转换为double。进行此转换的决定是在编译时执行的。 (您所说的“'C 方式'”实际上并不是执行隐式转换的 C 方式;而是绕过 C 的隐式转换的结果。)
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 2011-03-01
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多