我认为视图函数的工作方式类似于 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
Run Code Online (Sandbox Code Playgroud)
基本上你改变一个,另一个也改变,反之亦然。但这并没有相同的效果:
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
Run Code Online (Sandbox Code Playgroud)
我的问题:这相当于只是做:a[3, :] = a[1, :]?是否有任何性能优势?第二种情况的幕后发生了什么?
任何反馈表示赞赏!
您可以通过运行以下代码来检查这种情况下是否发生复制:
\njulia> a = rand(3, 10^6);\n\njulia> b = view(a, 1, :);\n\njulia> @time a[3, :] = b; # I have already compiled the code earlier\n 0.005599 seconds (3 allocations: 7.629 MiB)\n\njulia> bc = copy(b);\n\njulia> @time a[3, :] = bc; # I have already compiled the code earlier\n 0.002189 seconds (1 allocation: 16 bytes)\nRun Code Online (Sandbox Code Playgroud)\n原因是 Julia 在函数中_unsafe_setindex!(即最终由您执行的操作调用)执行x\xe2\x80\xb2 = unalias(A, x). 此操作意味着在编译时检查是否保证源数组和目标数组不共享内存。在这种情况下,编译器无法证明这一点,因此会发生复制。
为了使您想要的操作高效,您可以做的就是使用循环(正如您所知,实际上别名不会通过您定义操作的方式发生;我正在使用视图,但当然您可以只读取和写入直接来自a而不创建b):
function fastcopy!(a)\n @assert size(a, 1) > 2\n b = view(a, 1, :)\n @inbounds @simd for i in eachindex(b)\n a[3, i] = b[i]\n end\nend\nRun Code Online (Sandbox Code Playgroud)\n时间安排如下:
\njulia> @time fastcopy!(a)\n 0.001895 seconds\nRun Code Online (Sandbox Code Playgroud)\n