我试图尽可能地过度简化这一点。
函数f1
和f2
在向量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个多小时而无法找到答案......即使这些功能是通过使用虽然循环我不想知道发生了什么。
感谢。
答案 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).