在Julia语言中,如何重用函数编译? 在Julia语言中,如何重用函数编译?

4
我在尝试使用Julia,遇到了一个与编译器/JIT编译方案有关的问题。如果我编写了一个函数,例如:
function f(x) 
  return mapreduce(*,+,x,x)
end

由于这个函数适用于抽象数组,所以在使用前不可能知道其形状,因此无法编译。如果在函数 g 中使用它,该函数的输入应为浮点数数组的数组,如下所示:

function g(y) 
  return mapreduce(f,+,y)
end

或者,另一种选择是

function g2(y) 
  res = 0 
  for x in y 
    res = res + f(x)
  end
  return res 
end 

然后,当我们使用g时,比如说g([[1,2],[3,4]]),最终会调用f函数。假设它首先在[1,2]上被调用,然后被编译和评估。在我看来,由于f([3,4])f([1,2])具有完全相同的类型,即都是二维数组,因此f将被重用。但是,当我输入@code_llvm(f([1,2]))@code_llvm(f([3,4]))时,我发现函数名称是不同的(它们有一个共同前缀,类似于julia_f_,后面跟着一个数字)。此外,如果我再次调用@code_llvm(f([1,2])),我会得到另一个名称。
Julia确实允许g对于每个应用程序重复使用已编译版本的f函数吗?这是否取决于涉及的数组长度;即在g([w1,...,wn])中,每个wi是否都必须具有相同的长度才能重复使用f函数?

1
我认为这只是一个打印问题(或者可能是通过@code_llvm查看实现的副作用)。那些内部函数名称并不准确反映Julia在实践中的操作。 - mbauman
这并不能完全回答这个问题,但是它可能有所帮助: https://julialang.org/blog/2020/08/invalidations/#method_invalidation_what_is_it_and_when_does_it_happen - BallpointBen
1个回答

5

我对Julia的内部机制不太了解,但也许这可以证明f只被编译一次:

function f(x) 
    mapreduce(*, +, x, x)
end

function g(y) 
    mapreduce(f, +, y)
end

julia> @time g([[1, 2], [3, 4]])
  0.099061 seconds (322.72 k allocations: 19.687 MiB, 99.94% compilation time)
30

julia> @time g([[1, 2], [3, 4]])
  0.000021 seconds (11 allocations: 672 bytes)
30

g 第一次运行时,99.94%的时间用于编译。第二次运行 g 时,0%的时间用于编译。请注意,如果要从 @time 宏获取编译时间,则需要使用 Julia v1.6+。


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