向函数传递函数时,Julia 编译器似乎没有进行优化 [英] Julia compiler does not appear to optimize when a function is passed a function

查看:17
本文介绍了向函数传递函数时,Julia 编译器似乎没有进行优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第二次 github 上的这个拉取请求将解决问题.只要运行 Julia v0.5+,匿名函数就和普通函数一样快.所以案件结束了.

SECOND This pull request on github will fix the issue. As long as one is running Julia v0.5+, anonymous functions will be just as fast as regular functions. So case closed.

我已将问题和函数定义更新为更一般的情况.

I've updated the question and function definitions to a more general case.

举个简单的例子,当一个函数被传递给一个函数或者一个函数被定义在一个函数中时,Julia 编译器似乎并没有进行优化.这让我感到惊讶,因为这在优化包中很常见.我是正确的还是我在做一些愚蠢的事情?一个简单的例子如下:

For a simple example, the Julia compiler does not appear to optimize when a function is passed a function or a function is defined within a function. This surprises me as surely this is very common in optimization packages. Am I correct or am I doing something stupid? A simple example follows:

f(a::Int, b::Int) = a - b    #A simple function

function g1(N::Int, fIn::Function)   #Case 1: Passing in a function
    z = 0
    for n = 1:N
        z += fIn(n, n)
    end
end

function g2(N::Int)   #Case 2: Function defined within a function
    fAnon = f
    z = 0
    for n = 1:N
        z += fAnon(n, n)
    end
    return(z)
end

function g3(N::Int)   #Case 3: Function not defined within function
    z = 0
    for n = 1:N
        z += f(n, n)
    end
    return(z)
end

然后我运行以下代码对这三种情况进行计时:

Then I run the following code to time the three cases:

#Run the functions once
g1(10, f)   
g2(10)
g3(10)

@time g1(100000000, f)
@time g2(100000000)
@time g3(100000000)

时间安排是:

elapsed time: 5.285407555 seconds (3199984880 bytes allocated, 33.95% gc time)
elapsed time: 5.424531599 seconds (3199983728 bytes allocated, 32.59% gc time)
elapsed time: 2.473e-6 seconds (80 bytes allocated)

前两种情况需要大量内存分配和垃圾回收.谁能解释一下原因?

Lots of memory allocation and garbage collection for the first two cases. Could anyone explain why?

推荐答案

所以一个有趣的事情是在 Julia 0.4 中使用 @code_warntype,显示如下:

So a fun thing to do is use @code_warntype in Julia 0.4, which shows the following:

julia> @code_warntype g1(10, f)
Variables:
  N::Int64
  fIn::F
  z::Any
  #s1::Int64
  n::Int64

Body:
  begin  # none, line 2:
      z = 0 # line 3:
... snip ....
      z = z + (fIn::F)(n::Int64,n::Int64)::Any::Any

所以问题在于 f 的返回类型的推断,这实际上可能是任何东西.问题(据我所知)是 Julia 为每种类型组合编译了一个方法.我们已经为 any 函数生成了代码,所以任何东西都可以返回.如果 Function 是返回类型的参数,那就太好了,因为这样我们就可以做一些更聪明的事情,比如 Function{T<:Any,Int}.

So the problem is with inference of the return type of f, which really could be anything. The problem (as I understand it) is that Julia compiles a method for each type combination. We've got code generated here for any function, so anything could come back. It'd be neat if Function was parametric on the return type, because then we could do something smarter like Function{T<:Any,Int}.

我的解决方案是把它改成 z += fIn(n, n)::Int,这样 z 就可以一直是 Int 但我还是看到了

My solution was to change it to z += fIn(n, n)::Int, and that allows z to always be an Int but I still see

(top(typeassert))((fIn::F)(n::Int64,n::Int64)::Any,Int)::Int64

@code_warntype 输出中,这是有道理的,因为它确实仍然是一个 Any,我只是确保它不会污染其余部分.但我认为它仍然需要生成代码来检查它实际上是一个 Int.让我们称这个新版本为 g1A:

in the @code_warntype output, which makes sense, because it really is still an Any, I'm just making sure that doesn't pollute the rest. But I think it still has to generate code to check it is in fact an Int. Lets call this new version g1A:

julia> @time g1(1000000, f)
elapsed time: 0.124437357 seconds (30 MB allocated, 2.82% gc time in 1 pauses with 0 full sweep)
elapsed time: 0.121653131 seconds (30 MB allocated, 2.51% gc time in 2 pauses with 0 full sweep)
elapsed time: 0.120805345 seconds (30 MB allocated, 1.17% gc time in 1 pauses with 0 full sweep)

julia> @time g1A(1000000, f)
elapsed time: 0.085875439 seconds (30 MB allocated, 5.20% gc time in 1 pauses with 0 full sweep)
elapsed time: 0.074592531 seconds (30 MB allocated, 4.67% gc time in 2 pauses with 0 full sweep)
elapsed time: 0.078681071 seconds (30 MB allocated, 4.75% gc time in 1 pauses with 0 full sweep)

所以有些收获,但并不理想.这是一个深入 Julia 内部工作的已知问题.相关讨论:

So some gains, but not ideal. This is a known issue that goes deep into Julia's inner workings. Related discussion:

这篇关于向函数传递函数时,Julia 编译器似乎没有进行优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆