【问题标题】:when is vectorization favored in Julia?Julia 什么时候支持向量化?
【发布时间】:2015-02-21 16:53:36
【问题描述】:

我有 2 个函数用于在 Julia 中以数字方式确定 pi。第二个函数(我认为是矢量化的)比第一个慢。 为什么矢量化较慢?是否有规则何时进行矢量化,何时不进行矢量化?

function determine_pi(n)
    area = zeros(Float64, n);
    sum = 0;
    for i=1:n
        if ((rand()^2+rand()^2) <=1)
            sum = sum + 1;
        end
            area[i] = sum*1.0/i;
    end
    return area
end

还有另一个功能

function determine_pi_vec(n)
    res = cumsum(map(x -> x<=1?1:0, rand(n).^2+rand(n).^2))./[1:n]
    return res
end

运行 n=10^7 时,以下是执行时间(运行几次后)

n=10^7
@time returnArray = determine_pi(n)
#output elapsed time: 0.183211324 seconds (80000128 bytes allocated)
@time returnArray2 = determine_pi_vec(n);
#elapsed time: 2.436501454 seconds (880001336 bytes allocated, 30.71% gc time)

【问题讨论】:

    标签: vectorization julia


    【解决方案1】:

    如果

    • 它使代码更易于阅读,性能并不重要
    • 如果它是线性代数运算,则使用矢量化样式可能会很好,因为 Julia 可以使用 BLAS 和 LAPACK 以非常专业的高性能代码执行您的运算。

    总的来说,我个人认为最好从矢量化代码开始,寻找任何速度问题,然后对任何麻烦的问题进行去矢量化。

    您的第二个代码之所以慢,倒不是因为它被矢量化了,而是因为使用了匿名函数:不幸的是,在 Julia 0.3 中,这些代码通常会慢很多。 map 通常表现不佳,我相信是因为 Julia 无法推断函数的输出类型(从 map 函数的角度来看,它仍然是“匿名的”)。我写了一个不同的矢量化版本,它避免了匿名函数,并且可能更容易阅读:

    function determine_pi_vec2(n)
        return cumsum((rand(n).^2 .+ rand(n).^2) .<= 1) ./ (1:n)
    end
    

    基准测试

    function bench(n, f)
      f(10)
      srand(1000)
      @time f(n)
      srand(1000)
      @time f(n)
      srand(1000)
      @time f(n)
    end
    
    bench(10^8, determine_pi)
    gc()
    bench(10^8, determine_pi_vec)
    gc()
    bench(10^8, determine_pi_vec2)
    

    给我结果

    elapsed time: 5.996090409 seconds (800000064 bytes allocated)
    elapsed time: 6.028323688 seconds (800000064 bytes allocated)
    elapsed time: 6.172004807 seconds (800000064 bytes allocated)
    elapsed time: 14.09414031 seconds (8800005224 bytes allocated, 7.69% gc time)
    elapsed time: 14.323797823 seconds (8800001272 bytes allocated, 8.61% gc time)
    elapsed time: 14.048216404 seconds (8800001272 bytes allocated, 8.46% gc time)
    elapsed time: 8.906563284 seconds (5612510776 bytes allocated, 3.21% gc time)
    elapsed time: 8.939001114 seconds (5612506184 bytes allocated, 4.25% gc time)
    elapsed time: 9.028656043 seconds (5612506184 bytes allocated, 4.23% gc time)
    

    所以在某些情况下,向量化的代码绝对可以和去向量化的代码一样好,即使我们不在线性代数的情况下也是如此。

    【讨论】:

    • 谢谢。我更改了第二个代码以删除匿名函数,但它仍然表现不佳: function isInside(x) x
    • 匿名函数并不是最大的问题——更多的是map没有内联函数参数并生成专门的代码,而通过避免映射,可以内联isInside检查。
    • 哈哈,是的,我刚刚更新了我的答案以试图澄清这一点
    • 谢谢@StefanKarpinski 和@iainDunning!我按照您的建议删除了map,它几乎将性能提高了 2 倍。是否有规则可以确定集合的函数(mapreduce 等)何时与直接使用循环一样好或更快在朱莉娅?
    猜你喜欢
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多