繁体   English   中英

朱莉娅-浏览结构中的数组的许多分配

[英]Julia - many allocation to browse an array in struct

我目前正在为茱莉亚的怪异行为而挣扎。 我正在浏览数组,无论数组是否在struct内部,Julia的行为都不相同。

对于结构内部的数组,许多分配似乎毫无意义。 具体来说,分配的数量与数组的大小一样多。

这是复制此问题的代码:

function test1()
    a = ones(Float32, 256)

    for i = 1:256
        a[i]
    end
end

struct X
    mat
end

function test2()
    a = X(ones(Float32, 256))

    for i = 1:256
        a.mat[i]
    end
end

function main()
    test1()
    test2()

    @time test1()
    @time test2()
end

main()

和我得到的输出:

0.000002 seconds (1 allocation: 1.141 KiB)
0.000012 seconds (257 allocations: 5.141 KiB)

起初我以为这是一个类型问题,但我不强迫这样做,并且循环后类型也没有不同。

谢谢你的帮助。

您需要在struct指定mat的类型。 否则,使用X的函数将不会专门化并且不会进行充分优化。

没有类型注释的字段默认为Any,因此可以保存任何类型的值。 https://docs.julialang.org/en/v1/manual/types/index.html#Composite-Types-1

将您的结构定义更改为

struct X
    mat::Vector{Float32}
end

将解决问题。 现在的结果是:

  0.000000 seconds (1 allocation: 1.141 KiB)
  0.000000 seconds (1 allocation: 1.141 KiB)

如果更改代码中的一件事,您实际上可以通过@code_warntype宏看到效果。

for i = 1:256
    a.mat[i]
end

这部分实际上并没有做太多。 要查看@code_warntype的效果, @code_warntype旧代码中的这一行更改为

for i = 1:256
    a.mat[i] += 1.
end

结果@code_warntype会给Any的红色,你通常应该避免。 原因是在编译时不知道mat的类型。

> @code_warntype test2() # your test2() with old X def
Body::Nothing
1 ─ %1  = $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Float32,1}, svec(Any, Int64), :(:ccall), 2, Array{Float32,1}, 256, 256))::Array{Float32,1}
│   %2  = invoke Base.fill!(%1::Array{Float32,1}, 1.0f0::Float32)::Array{Float32,1}
└──       goto #7 if not true
2 ┄ %4  = φ (#1 => 1, #6 => %14)::Int64
│   %5  = φ (#1 => 1, #6 => %15)::Int64
│   %6  = (Base.getindex)(%2, %4)::Any <------ See here
│   %7  = (%6 + 1.0)::Any
│         (Base.setindex!)(%2, %7, %4)
│   %9  = (%5 === 256)::Bool
└──       goto #4 if not %9
3 ─       goto #5
4 ─ %12 = (Base.add_int)(%5, 1)::Int64
└──       goto #5
5 ┄ %14 = φ (#4 => %12)::Int64
│   %15 = φ (#4 => %12)::Int64
│   %16 = φ (#3 => true, #4 => false)::Bool
│   %17 = (Base.not_int)(%16)::Bool
└──       goto #7 if not %17
6 ─       goto #2
7 ┄       return

现在使用X的新定义,您将在@code_warntype结果中@code_warntype每个类型的推断。

如果希望X.mat保留其他类型的Vector或值,则可能需要使用Parametric Types 使用参数类型时,编译器仍将能够优化您的函数,因为在编译期间会知道类型。 我真的建议您阅读有关类型性能提示的相关手册条目。

  1. 切勿在结构定义中使用抽象类型。 在您的示例中,Julia需要存储变量指针而不是仅存储值,因此会降低速度。 而是使用参数类型:
julia> struct X{T}
           mat::T
           end

julia> X{Float64}.(1:3)
5-element Array{X{Float64},1}:
 X{Float64}(1.0)
 X{Float64}(2.0)
 X{Float64}(3.0)
  1. 如果不确定,请考虑使用@code_warntype宏来查看Julia编译器无法正确识别类型的位置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM