Julia 的 view 函数背后发生了什么?a[3, :] = view(a, 1, :) 和 a[3, :] = a[1, :] 有什么区别?

7

我认为视图函数的工作方式类似于C ++中的引用,基本上两个变量都指向同一块内存。

为什么这样可以工作:

julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9


julia> b = view(a, 1, :)
3-element view(::Array{Int64,2}, 1, :) with eltype Int64:
 1
 2
 3

julia> b[1] = 100
100

julia> a
3×3 Array{Int64,2}:
 100  2  3
   4  5  6
   7  8  9

julia> a[1, 3] = 200
200

julia> b
3-element view(::Array{Int64,2}, 1, :) with eltype Int64:
 100
   2
 200

基本上,你改变了一个,另一个也会改变,反之亦然。但这不会产生相同的效果:

julia> a = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9

julia> a[3, :] = view(a, 1, :)
3-element view(::Array{Int64,2}, 1, :) with eltype Int64:
 1
 2
 3

julia> a
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 1  2  3

julia> a[1, 1] = 100
100

julia> a
3×3 Array{Int64,2}:
 100  2  3
   4  5  6
   1  2  3

julia> a[3, 1] = 200
200

julia> a
3×3 Array{Int64,2}:
 100  2  3
   4  5  6
 200  2  3

我的问题是:这是否等同于仅仅执行:a[3, :] = a[1, :]?这两者是否有任何性能上的优势?在第二种情况背后发生了什么?感谢任何反馈!
1个回答

4
您可以通过运行以下代码来检查在此情况下的复制是否发生:
```html

您可以通过运行以下代码来检查在此情况下的复制是否发生:

```
julia> a = rand(3, 10^6);

julia> b = view(a, 1, :);

julia> @time a[3, :] = b; # I have already compiled the code earlier
  0.005599 seconds (3 allocations: 7.629 MiB)

julia> bc = copy(b);

julia> @time a[3, :] = bc; # I have already compiled the code earlier
  0.002189 seconds (1 allocation: 16 bytes)

原因在于Julia中的函数_unsafe_setindex!(由你执行的操作最终调用此函数),会执行x′ = unalias(A, x)。该操作会检查源数组和目标数组是否在编译时保证不共享内存。在这种情况下,编译器无法证明这一点,因此会进行复制操作。
为了使您想要执行的操作高效,您可以使用循环(因为您知道按照您定义操作的方式实际上不会发生别名; 我正在使用一个视图,但是您当然可以直接从a读取和写入而无需创建b):
function fastcopy!(a)
    @assert size(a, 1) > 2
    b = view(a, 1, :)
    @inbounds @simd for i in eachindex(b)
        a[3, i] = b[i]
    end
end

以下是时间安排:

julia> @time fastcopy!(a)
  0.001895 seconds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接