首页 > 解决方案 > Julia 代码优化,结构和原始类型之间的区别?(内存分配)

问题描述

我有一些代码可以优化一些我不希望 gc 触发内存分配的关键部分。

更准确地说,我有一个实数类型

struct AFloat{T<:AbstractFloat} <: Real
    value::T
    j::Int 
end

我必须跟踪以执行自动微分。因此,对于任何算术运算,我都必须在磁带上进行一些注册。性能在这里非常重要(如果您在每个算术运算中再分配一个分配器,这会产生真正的不同!)。我可以选择AFloat{T}或简单地使用原始类型来跟踪索引 j:

primitive type AFloat64 <: Real sizeof(Int) end

但是,我对这些结果感到困惑:

第一部分:好的

using BenchmarkTools

struct A n::Int64 end

vA=A[A(1)];
@time push!(vA,A(2))

v=Int64[1];
@time push!(v,2)

返回

0.000011 seconds (6 allocations: 224 bytes)
0.000006 seconds (5 allocations: 208 bytes)

这与以下内容一致:

@btime push!(vA,A(2))
@btime push!(v,2)

返回

  46.410 ns (1 allocation: 16 bytes)
  37.890 ns (0 allocations: 0 bytes)

-> 我会得出结论,与结构相比,推动原始类型避免了一次内存分配(对吗?)

第二部分:……有问题……?!

在这里我很困惑,我无法解释这些结果:

foo_A() = A(1);             
foo_F64() = Float64(1.);                
foo_I64() = Int64(1);             

@time foo_A()
@time foo_F64()
@time foo_I64()

返回

  0.000004 seconds (5 allocations: 176 bytes)
  0.000005 seconds (5 allocations: 176 bytes)
  0.000005 seconds (4 allocations: 160 bytes)

Q1 如何解释差异 foo_F64() vs foo_I64() (5 allocs vs 4 allocs)?

此外,结果似乎与@btime 输出不一致:

@btime foo_A()
  3.179 ns (0 allocations: 0 bytes)

@btime foo_F64()
  3.801 ns (0 allocations: 0 bytes)

@btime foo_I64()
  3.180 ns (0 allocations: 0 bytes)

Q2:@time 或@btime 的正确答案是什么?为什么?

综合来说,在 Julia 中, foo_Afoo_Primitive在性能和内存分配方面是否存在差异,其中:

struct A n::Int64 end

foo_A() = A(1)
foo_Primitive() = Int64(1)

我知道使用@time 或@btime 时,使用如此小的表达式确实存在副作用的风险。理想情况下,最好了解 Julia 的内部知识来回答。但我不


julia> versioninfo()
Julia Version 0.6.2
Commit d386e40c17 (2017-12-13 18:08 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Xeon(R) CPU E5-2603 v3 @ 1.60GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, haswell)

标签: optimizationjulia

解决方案


您看到的分配只是 REPL afaict 时间的副作用。
如果你把它们放在一个函数中,那么无论你使用的是结构体还是原始类型,分配都是一样的:

julia> function f()
           vA=[A(1)]
           @time push!(vA,A(2))

           v=[1]
           @time push!(v,2)
       end
f (generic function with 1 method)

julia> f();
  0.000000 seconds (1 allocation: 32 bytes)
  0.000000 seconds (1 allocation: 32 bytes)

推荐阅读