当前位置: 首页 > 知识库问答 >
问题:

Julia代码中的内存分配问题

吴高峰
2023-03-14

我使用Python/Numpy中的一个函数来解决组合博弈论中的一个问题。

import numpy as np
from time import time

def problem(c):
    start = time()
    N = np.array([0, 0])
    U = np.arange(c)
    
    for _ in U:
        bits = np.bitwise_xor(N[:-1], N[-2::-1])
        N = np.append(N, np.setdiff1d(U, bits).min())

    return len(*np.where(N==0)), time()-start 

problem(10000)

然后我在Julia中编写了它,因为我认为它会更快,因为Julia使用即时编译。

function problem(c)
    N = [0]
    U = Vector(0:c)
    
    for _ in U
        elems = N[1:length(N)-1]
        bits = elems .⊻ reverse(elems)
        push!(N, minimum(setdiff(U, bits))) 
    end
    
    return sum(N .== 0)
end

@time problem(10000)

但第二个版本要慢得多。对于c=10000,Python版本需要2.5秒。在核心i5处理器上,Julia版本需要4.5秒。由于Numpy操作是用C实现的,我想知道Python是否真的更快,或者我是在编写一个具有浪费时间复杂性的函数。

Julia中的实现分配了大量内存。如何减少分配数量来提高其性能?

共有1个答案

狄珂
2023-03-14

原始代码可以通过以下方式重写:

function problem2(c)
    N = zeros(Int, c+2)
    notseen = falses(c+1)

    for lN in 1:c+1
        notseen .= true
        @inbounds for i in 1:lN-1
            b = N[i] ⊻ N[lN-i]
            b <= c && (notseen[b+1] = false)
        end
        idx = findfirst(notseen)
        isnothing(idx) || (N[lN+1] = idx-1)
    end
    return count(==(0), N)
end

首先检查函数是否产生相同的结果:

julia> problem(10000), problem2(10000)
(1475, 1475)

(我还检查了生成的N向量是否相同)

现在让我们对这两个功能进行基准测试:

julia> using BenchmarkTools

julia> @btime problem(10000)
  4.938 s (163884 allocations: 3.25 GiB)
1475

julia> @btime problem2(10000)
  76.275 ms (4 allocations: 79.59 KiB)
1475

所以结果是速度超过60倍。

我为提高性能所做的是避免分配。在朱莉娅,这是容易和高效的。如果代码的任何部分不清楚,请评论。请注意,我集中展示了如何提高Julia代码的性能(而不是试图仅仅复制Python代码,因为-正如在原始的后处理语言性能比较下所评论的那样,这是非常棘手的)。我认为最好在这次讨论中集中讨论如何使Julia代码快速。

实际上,更改为Vector{Bool}并删除bc关系上的条件(从数学上来说,这些c的值适用)可以提供更好的速度:

julia> function problem3(c)
           N = zeros(Int, c+2)
           notseen = Vector{Bool}(undef, c+1)

           for lN in 1:c+1
               notseen .= true
               @inbounds for i in 1:lN-1
                   b = N[i] ⊻ N[lN-i]
                   notseen[b+1] = false
               end
               idx = findfirst(notseen)
               isnothing(idx) || (N[lN+1] = idx-1)
           end
           return count(==(0), N)
       end
problem3 (generic function with 1 method)

julia> @btime problem3(10000)
  20.714 ms (3 allocations: 88.17 KiB)
1475
 类似资料:
  • 我使用Keras/Tensorflow在python中创建了一个程序。我对数据的创建和训练没有任何问题。但是,当我想评估我的模型时,我有以下错误: 这似乎是一个内存分配问题。我缩小了模型的尺寸,缩小了所有参数,但没有任何变化。我不知道如何解决这个问题。

  • 我在运行OSX 10.13.6的Mac上有PHP版本7.2.9。如果我加载phpinfo(),我在Safari中看到memory_limit=256M。然而,当我看php.ini(/usr/本地/php5/lib/php.ini)memory_limit=128M。这种差异的原因是什么——显然限制是在其他地方设定的,但是在哪里?我需要增加内存限制

  • 问题内容: 类B继承了类A。现在,当我们创建类型B的对象时,为B分配的内存是多少?是否包括A和B或任何其他内存分配过程? 问题答案: 当创建对象B时,假设调用了默认构造函数 然后,JVM分配具有更多或更少内容的对象: 在B中显式声明的每个字段都有足够的内存(每个字段通常大约4-8字节,但是类型和主机系统之间有很大差异) 对于A及其祖先继承的每个最终字段,都有足够的内存 足够的内存来包含对调度向量的

  • 问题内容: 当您知道on上对象/项目的确切数量时,我非常想知道哪种内存分配方法对性能(例如,运行时间)有利,这对性能有好处。少量对象(少量内存)和大量对象(大量内存)的成本。 与 请告诉我。谢谢。 注意:我们可以对此进行基准测试,并且可能知道答案。但是我想知道解释这两种分配方法之间性能差异的概念。 问题答案: 静态分配将更快。静态分配可以在全局范围和堆栈上进行。 在全局范围内,静态分配的内存内置在

  • 我正在使用带有Spring框架的tomcat-7和java-8。我刚刚在webapps中部署了一个应用程序。之后,我监控了Visual alvm中的内存,下面是截图。 tomcat上没有命中,使用的堆正在增加,并且在执行了限制GC之后。我想知道,如果这是正常行为还是我的Web应用程序有问题。

  • 我有一个关于java如何处理未使用变量的问题。 假设我有以下代码: 那么我就不会在代码中使用notUsedVariable。该变量是否会被存储,或者java是否足够聪明,可以在编译时忽略该变量? 谢谢