据我所知,Julia严重依赖于即时静态类型派生(基本上所有代码都需要被视为c ++模板)。我也知道这意味着在不同类型的对象上使用单个算法时只要在编译时知道这些类型就没有运行时开销。
当涉及到运行时多态性时,我对事情的运作方式不太清楚。假设我们有以下情况:
abstract Shape
type Circle <: Shape
radius::Float64
end
type Square <: Shape
width::Float64
end
dist(x::Circle, y::Circle) = ...
dist(x::Circle, y::Square) = ...
dist(x::Square, y::Circle) = ...
dist(x::Square, y::Square) = ...
s = get_shape()
t = get_shape()
a = dist(s,t)
此处,get_shape
可以返回圆形或方形,基于例如用户输入。在c ++中,dispatch只需要进行虚拟表查找。这在朱莉娅是如何运作的?多次发送背后的机制是什么?虚拟表查找是否明显更昂贵?从同一抽象类型中导出Square
和Circle
有什么好处,还是在运行时调度的上下文中完全不相关?
EDT:在此示例中运行@code_warntype给出:
Variables:
s::Union{Circle,Square}
t::Union{Circle,Square}
Body:
begin # none, line 2:
s = (Main.get_shape)()::Union{Circle,Square} # none, line 3:
t = (Main.get_shape)()::Union{Circle,Square} # none, line 4:
return (Main.dist)(s::Union{Circle,Square},t::Union{Circle,Square})::ASCIIString
end::ASCIIString
因此编译器对s和t的类型并不完全无能为力。在调用dist
时,这些知识是否用于加快调度?
答案 0 :(得分:8)
当你有多个相同函数的方法时,julia使用类型交集的方法查找(匹配签名中类型的参数类型)来确定调用哪个方法。如果可以推断出类型,则可以在编译代码时执行该计算。通过提前查找,它不必在运行时执行类型交集,这样可以获得最佳性能。
当类型不可预测时,julia必须确定在运行时调度哪个方法。如果被调用的函数正在进行大量的工作,这有时可能是运行时的瓶颈。 (当它做了很多工作时,查找基本上对性能无关紧要)。
julia比OOP语言稍微复杂一点,因为正确的方法取决于所有的参数,而不仅仅是第一个。
答案 1 :(得分:0)
我知道这很古老,但是如果有人对数字感兴趣,我会发现一点benchmark。事实证明,当前(1.1)使用抽象类型的运行时多态性非常慢(相对于静态调度而言,是30倍,对于C ++虚拟函数而言,是6倍)。