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

查看:94
本文介绍了当函数传递函数时,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)

有一些收获,但并不理想.这是一个众所周知的问题,深入到朱莉娅的内部运作中.相关讨论:

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

  • #1090 return type declarations
  • #210 function types
  • #1864 anonymous function calls have a huge overhead
  • #9863 Someone needs to write a FAQ entry on functions-as-variables

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

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