将@time报告的分配给Julia中大向量的分配加倍

问题描述 投票:2回答:2

请在Julia中考虑以下简单程序:

function foo_time(x)
    @time x.^2
    return nothing
end
n = 1000;
foo_time(collect(1:n));

如果我在控制台中运行该命令,则@time报告1个分配,这是我期望的。但是,如果我将n更改为10000,则@time报告2个分配。

而且,如果我将函数链接在一起而没有语法循环融合(换句话说,没有点),那么我似乎得到了预期分配的两倍。例如,用(x + x).^2 + x代替x.^2n = 1000会产生3个分配,但是n = 10000会产生6个分配。 (不过,该模式并未严格继续:例如,(x + x + x).^2仅产生n = 10000 5个分配。)

为什么向量的大小会影响发生多少分配?这是怎么回事?

这在JupyterLab控制台和普通的Julia REPL中都发生。

time julia allocation
2个回答
4
投票

为什么有一个小向量分配,而两个大向量分配?

真的,这无关紧要,它是数组如何工作的内部细节。本质上,Julia Array有两个部分:内部标头(跟踪数组的维数和元素类型等)以及数据本身。当阵列较小时,将这两个数据段捆绑在一起是有优势的,但是当阵列较大时,将它们分开是有利的。这不是广播,而是数组分配:

julia> f(n) = (@time Vector{Int}(undef, n); nothing)
f (generic function with 1 method)

julia> f(2048)
  0.000003 seconds (1 allocation: 16.125 KiB)

julia> f(2049)
  0.000003 seconds (2 allocations: 16.141 KiB)

然后希望您能看到为什么在涉及临时对象的情况下,这导致大型数组分配数量增加一倍的原因-每个数组的头有一个,每个数组的数据有一个。

简而言之,不必担心分配数量。有时候分配实际上可以提高性能。不过,值得关注的是,当您看到大量的分配时-特别是如果您可以看到它们与数组中元素的数量成正比。


0
投票

我同意Matt的观点,对于这个简单的任务,分配数量并不是一个好的指标。

[如果您想深入了解细节并准确了解代码的编译和执行方式,建议您使用这些宏@code_llvm@code_lowered@code_native@code_typed@code_warntype。这些宏之间的所有子实用程序都在[julia doc。]中进行了详细说明。

julia> f(x) = x.^2
f (generic function with 1 method)

julia> @code_lowered f(randn(10000))
CodeInfo(
1 ─ %1 = (Core.apply_type)(Base.Val, 2)
│   %2 = (%1)()
│   %3 = (Base.broadcasted)(Base.literal_pow, Main.:^, x, %2)
│   %4 = (Base.materialize)(%3)
└──      return %4
)

julia> f2(x) = (x + x).^2 + x
f2 (generic function with 1 method)

julia> @code_lowered f2(randn(10000))
CodeInfo(
1 ─ %1 = x + x
│   %2 = (Core.apply_type)(Base.Val, 2)
│   %3 = (%2)()
│   %4 = (Base.broadcasted)(Base.literal_pow, Main.:^, %1, %3)
│   %5 = (Base.materialize)(%4)
│   %6 = %5 + x
└──      return %6
)
© www.soinside.com 2019 - 2024. All rights reserved.