2016-03-23 71 views
4

我有一個算法,需要一列數組替換爲相同數組的另一列。 我試着用切片和元素做它。複製數組列

const M = 10^4 
const N = 10^4 
A = rand(Float32, M, N) 
B = rand(Float32, N, M) 

function copy_col!(A::Array{Float32,2},col1::Int,col2::Int) 
    A[1:end,col2] = A[1:end,col1] 
end 

function copy_col2!(A::Array{Float32,2},col1::Int,col2::Int) 
    for i in 1:size(A,1) 
    A[i,col2] = A[i,col1] 
    end 
end 

[Both functions+rand are called here once for compilation] 

@time (for i in 1:20000 copy_col!(B, rand(1:size(B,2)),rand(1:size(B,2))); end) 
@time (for i in 1:20000 copy_col2!(B, rand(1:size(B,2)),rand(1:size(B,2))); end) 

>> 0.607899 seconds (314.81 k allocations: 769.879 MB, 25.05% gc time) 
>> 0.213387 seconds (117.96 k allocations: 2.410 MB) 

爲什麼使用切片進行復制的表現要差得多?有沒有比copy_col2!更好的方法?

回答

7

A[1:end,col1]首先創建索引列的副本,然後複製到A[1:end,col2],因此copy_col!分配更多,運行時間更長。在這種情況下,有sub,sliceview可以補救分配。

+0

謝謝,我應該更徹底地閱讀文檔。事實上,使用'sub'具有與元素智能副本相同的運行時。仍然需要更多的分配,但沒關係。看起來也很乾淨。你不知道如何進一步優化? – skleinbo

+0

我認爲使用'sub'和別人分配一些是正常的,因爲它們將一列'A'包裹在一個新對象周圍。如果使用基於元素的副本,則可以使用@ @inbounds'(可能與@simd一起)進一步優化,如 ' @simd @inbounds for i in 1:size(A,1) A [i,col2] = A [我,col1] 結束 ' 我不知道如何反映這與'sub'的方法。另外,你做了'A [:,col1] = sub(A,:,col2)'?或者是其他東西? –

+0

我的確做到了。我會嘗試入站和simd併發布結果。但復活節後。 – skleinbo