gpt4 book ai didi

julia - 如何通过防止内存分配来提高 Julia 代码性能?

转载 作者:行者123 更新时间:2023-12-04 12:04:39 24 4
gpt4 key购买 nike

我正在阅读 Julia 性能提示,
https://docs.julialang.org/en/v1/manual/performance-tips/
一开始就提到了两个例子。
例一,

julia> x = rand(1000);

julia> function sum_global()
s = 0.0
for i in x
s += i
end
return s
end;

julia> @time sum_global()
0.009639 seconds (7.36 k allocations: 300.310 KiB, 98.32% compilation time)
496.84883432553846

julia> @time sum_global()
0.000140 seconds (3.49 k allocations: 70.313 KiB)
496.84883432553846
我们看到很多内存分配。
现在例子2,
julia> x = rand(1000);

julia> function sum_arg(x)
s = 0.0
for i in x
s += i
end
return s
end;

julia> @time sum_arg(x)
0.006202 seconds (4.18 k allocations: 217.860 KiB, 99.72% compilation time)
496.84883432553846

julia> @time sum_arg(x)
0.000005 seconds (1 allocation: 16 bytes)
496.84883432553846
我们看到,通过将 x 放入函数的参数中,内存分配几乎消失了,速度也快了很多。
我的问题是,谁能解释一下,
  • 为什么示例 1 需要这么多分配,为什么示例 2 不需要与示例 1 一样多的分配?
    我有点困惑。
  • 在这两个例子中,我们看到第二次运行 Julia 时,它总是比第一次快。
    这是否意味着我们需要运行 Julia 两次?如果 Julia 只在第二次运行时很快,那么重点是什么?为什么 Julia 不先编译,然后运行,就像 Fortran 一样?
  • 是否有阻止内存分配的一般规则?还是我们总是需要做一个@time 来确定问题?

  • 谢谢!

    最佳答案

    why example 1 needs so many allocation, and why example 2 does not need as many allocations as example 1?


    示例 1 需要如此多的分配,因为 x是一个全局变量(定义在函数的范围之外 sum_arg )。因此变量的类型 x可能随时发生变化,即有可能:
  • 您定义 xsum_arg
  • 你编译sum_arg
  • 你重新定义x (更改其类型)并运行 sum_arg

  • 特别是,由于 Julia 支持多线程,一般而言,步骤 3 中的两个操作甚至可以并行发生(即,您可以在一个线程中更改 x 的类型,而 sum_arg 将在另一个线程中运行)。
    所以因为编译后 sum_arg x的类型编译时可以更改 Julia sum_arg必须确保编译后的代码不依赖于 x 的类型这是在编译时出现的。相反,在这种情况下,Julia 允许类型为 x要动态更改。但是,这种动态特性允许 x意味着它必须在运行时(而不是编译时)进行检查。而这个 x 的动态检查导致性能下降和内存分配。
    你可以通过声明 x 来解决这个问题成为 const (因为 const 确保 x 的类型不会改变):
    julia> const x = rand(1000);

    julia> function sum_global()
    s = 0.0
    for i in x
    s += i
    end
    return s
    end;

    julia> @time sum_global() # this is now fast
    0.000002 seconds
    498.9290555615045

    Why not Julia just do a compiling first, then do a run, just like Fortran?


    这正是 Julia 所做的。但是,Julia 的好处是它会在需要时自动进行编译。这使您可以进行流畅的交互式开发过程。
    如果您愿意,可以在使用 precompile 运行之前编译该函数。函数,然后单独运行。然而,通常人们只是运行该函数而没有明确地执行它。
    结果是,如果你使用 @time :
  • 第一次运行函数时,它会返回执行时间和编译时间(正如您在粘贴的示例中看到的那样 - 您会获得编译所花费时间百分比的信息)。
  • 在连续运行中,函数已经被编译,所以只返回执行时间。

  • Is there any general rule to preventing memory allocations?


    这些规则完全在 Performance Tips 中给出。您在问题中引用的手册部分。使用小贴士 @time那里有一个诊断提示。所有其他提示都是为获得快速代码而推荐的规则。但是,我知道该列表很长,因此根据我的经验,可以从一个较短的列表开始:
  • Avoid global variables
  • Avoid containers with abstract type parameters
  • Write type stable functions
  • Avoid changing the type of a variable
  • 关于julia - 如何通过防止内存分配来提高 Julia 代码性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68572991/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com