while循环比返回迭代器

时间:2016-04-15 14:23:55

标签: performance for-loop while-loop julia

我试图尽可能地过度简化这一点。

函数f1f2在向量R上实现roulette wheel selection的非常简化版本。它们之间的唯一区别是f1使用for和f2一段时间。这两个函数都返回满足条件的数组的索引。

R=rand(100)

function f1(X::Vector)
    l = length(X)
    r = rand()*X[l]
    for i = 1:l
        if r <= X[i]
            return i
        end
    end    
end

function f2(X::Vector)
    l = length(X)
    r = rand()*X[l]
    i = 1
    while true
        if r <= X[i]
            return i
        end
        i += 1
    end    
end

现在我创建了几个测试功能...... M是我们重复执行函数的次数。

现在这很关键......我想存储我从函数中获得的值,因为我以后需要它们......为了过度简化代码,我刚刚创建了一个新的变量r,其中我总结了回报从功能。

function test01(M,R)
    cumR = cumsum(R)
    r = 0
    for i = 1:M
        a = f1(cumR)
        r += a
    end
    return r
end

function test02(M,R)
    cumR = cumsum(R)
    r = 0
    for i = 1:M
        a = f2(cumR)
        r += a
    end
    return r
end

所以,接下来我得到:

@time test01(1e7,R)
elapsed time: 1.263974802 seconds (320000832 bytes allocated, 15.06% gc time)

@time test02(1e7,R)
elapsed time: 0.57086421 seconds (1088 bytes allocated)

因此,出于某种原因,我无法弄清f1分配大量内存,而M得到的内存越大。  我说行r += a很关键,因为如果我从两个测试函数中删除它,我会在两个测试中得到相同的结果,所以没有问题!所以我认为函数返回的a类型存在问题(因为f1返回for循环的迭代器,f2使用自己的变量i }&#34;在函数内手动声明&#34;。

但是...

aa = f1(cumsum(R))
bb = f2(cumsum(R))
typeof(aa) == typeof(bb)

true

那......到底是怎么回事?

如果这是某种基本问题,我道歉但是,我现在已经过了3个多小时而无法找到答案......即使这些功能是通过使用虽然循环我不想知道发生了什么。

感谢。

2 个答案:

答案 0 :(得分:2)

当你看到许多令人惊讶的分配时,首先要检查的是type-stability@code_warntype宏在这里非常有用:

julia> @code_warntype f1(R)
# … lots of annotated code, but the important part is this last line:
  end::Union{Int64,Void}

将其与f2

进行比较
julia> @code_warntype f2(R)
# ...
  end::Int64

那么,为什么两者不同? Julia认为f1有时可能会返回nothing(类型为Void)!再看一下你的f1函数:如果X的最后一个元素是NaN,会发生什么?它只会在没有显式return语句的情况下脱离函数的末尾。但是,在f2中,您最终会超出X的范围进行索引,而是会出错。通过在没有找到答案的情况下完成循环来决定该怎么做来修复这种类型不稳定性,你会看到更多相似的时间。

答案 1 :(得分:0)

As I stated in the comment, your functions f1 and f2 both contain random numbers inside it, and you are using the random numbers as stopping criterion. Thus, there is no deterministic way to measure which of the functions is faster (doesn't depend in the implementation).

You can replace f1 and f2 functions to accept r as a parameter:

function f1(X::Vector, r)
    for i = 1:length(X)
        if r <= X[i]
            return i
        end
    end    
end

function f2(X::Vector, r)
    i = 1
    while i <= length(X)
        if r <= X[i]
            return i
        end
        i += 1
    end    
end

And then measure the time properly with the same R and r for both functions:

>>> R = cumsum(rand(100))
>>> r = rand(1_000_000) * R[end]  # generate 1_000_000 random thresholds

>>> @time for i=1:length(r); f1(R, r[i]); end;
0.177048 seconds (4.00 M allocations: 76.278 MB, 2.70% gc time)

>>> @time for i=1:length(r); f2(R, r[i]); end;
0.173244 seconds (4.00 M allocations: 76.278 MB, 2.76% gc time)

As you can see, the timings are now nearly identical. Any difference will be caused for external factors (warming or processor busy with other tasks).