【发布时间】:2017-06-28 22:46:38
【问题描述】:
据说 Julia for 循环与向量化操作一样快,甚至更快(如果使用得当的话)。 我有两段代码。这个想法是为给定的0-1序列找到一个样本统计量,即x(在这两个例子中,我试图找到一个总和,但还有更复杂的例子,我只是想理解一个一般含义我的代码中的性能缺陷)。第一个看起来像:
S = 2 * sum(x) - n
s_obs_new = abs(S) / sqrt(2 * n)
pval = erfc(s_obs_new)
第二个是“天真”和经典的东西:
S = 0
for i in eachindex(x)
S += x[i]
end
S = 2 * S - n
s_obs_new = abs(S) / sqrt(2 * n)
pval = erfc(s_obs_new)
使用@benchmark 我发现第一个示例的运行时间约为 11.8 毫秒,第二个示例的运行时间为 38 毫秒。
这个例子对我来说非常重要,因为在很多其他地方,矢量化是不可能的,所以我想以去矢量化的“方式”和矢量化一样快地进行计算。
有什么想法为什么去向量化的代码可能比向量化的代码慢 4 倍?类型稳定性还可以,没有不必要的大内存分配等。
第一个函数的代码是:
function frequency_monobit_test1( x :: Array{Int8, 1}, n = 0)
# count 1 and 0 in sequence, we want the number
# of 1's and 0's to be approximately the same
# reccomendation n >= 100
# decision Rule(at 1% level): if pval < 0.01 -> non-random
if (n == 0)
n = length(x)
end
S = 2 * sum(x) - n
s_obs_new = abs(S) / sqrt(2 * n)
pval = erfc(s_obs_new)
return pval
第二个是:
function frequency_monobit_test2( x :: Array{Int8, 1}, n = 0)
# count 1 and 0 in sequence, we want the number
# of 1's and 0's to be approximately the same
# reccomendation n >= 100
# decision Rule(at 1% level): if pval < 0.01 -> non-random
if (n == 0)
n = length(x)
end
S = 0
@inbounds for i in eachindex(x)
S += x[i]
end
S = 2 * S - n
s_obs_new = abs(S) / sqrt(2 * n)
pval = erfc(s_obs_new)
return pval
【问题讨论】:
-
首先,官方Performance Tips重要阅读
-
另一件要尝试的事情是将
@inbounds @simd放在for语句的前面 -
请向我们展示您为获得基准而运行的实际代码。
-
你能提供一些输入来测试代码吗?如何生成
x?另外,如果你想正确地计时代码,你应该使用github.com/JuliaCI/BenchmarkTools.jl,不要只在全局范围内使用@time。 -
你的两个代码sn-ps的唯一区别是你在第一个调用
sum,然后在第二个循环中手动累加。如果您使用@inbounds,它们应该同样快。此外,请确保将S初始化为正确的类型。x是整数还是浮点数?最好使用S = zero(eltype(x))而不是S = 0进行初始化。并使用BenchmarkTools.jl,正如我所提到的。
标签: performance for-loop vectorization julia