在画图时避免不必要的数组分配


#1

假设我们想绘制函数 z = f(x, y) = cos(x + y) 的三维曲面图形,xy 取值范围分别为 XY,则需要生成矩阵 ZZ,其中 ZZ[i, j] = f(X[i], Y[j]) = cos(X[i] + Y[j]),下面通过三种方式生成 ZZ

# 仿照 meshgrid
function f()
    X = 0:0.01:1
    Y = 0:0.01:1
    XX = repeat(X, 1, length(Y))
    YY = repeat(Y', length(X), 1)
    ZZ = cos.(XX .+ YY)
end

# 数组推导式
function g()
    X = 0:0.01:1
    Y = 0:0.01:1
    ZZ = [cos(x + y) for x in X, y in Y]
end

# 广播
function h()
    X = 0:0.01:1
    Y = 0:0.01:1
    ZZ = ((x, y) -> cos(x + y)).(X, Y')
end

在分别进行测试:

julia> @benchmark f()
BenchmarkTools.Trial:
  memory estimate:  239.48 KiB
  allocs estimate:  6
  --------------
  minimum time:     185.808 μs (0.00% GC)
  median time:      213.422 μs (0.00% GC)
  mean time:        241.130 μs (6.24% GC)
  maximum time:     61.227 ms (99.50% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> @benchmark g()
BenchmarkTools.Trial:
  memory estimate:  79.83 KiB
  allocs estimate:  2
  --------------
  minimum time:     133.725 μs (0.00% GC)
  median time:      140.434 μs (0.00% GC)
  mean time:        152.883 μs (6.26% GC)
  maximum time:     59.987 ms (99.67% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> @benchmark h()
BenchmarkTools.Trial:
  memory estimate:  79.83 KiB
  allocs estimate:  2
  --------------
  minimum time:     135.024 μs (0.00% GC)
  median time:      140.200 μs (0.00% GC)
  mean time:        157.678 μs (6.70% GC)
  maximum time:     62.370 ms (99.69% GC)
  --------------
  samples:          10000
  evals/sample:     1

可以看到类似于 meshgrid 的方式的开销是最大的,数组推导式和广播的方式则相差无几。


#2

我觉得你的主要意思是不必要的数组分配吧,因为第一个meshgrid函数分配了两个同等大小的数组XX与YY(作为中间结果),而不是标题说的矩阵复制


#3

的确如此,说数组分配会好一些,毕竟不是直接复制。