줄리아에서 부분배열 빠르게 참조하는 법
개요
줄리아에서 view
는 배열array의 부분배열subarray를 빠르게 참조하게끔 해주는 데이터 구조다1. 실제로 쓰는 입장에서는 번거롭기만하고 차이가 없어보이지만 게으르게lazily 참조되면서 더 가볍운 배열을 리턴한다. 따라서 아주 베이직한 수준에서까지 최적화된 줄리아 코드에서는 @views
라는 매크로를 쉽게 찾아볼 수 있다2.
코드
julia> M = rand(0:1,10,10)
10×10 Matrix{Int64}:
1 0 1 1 1 0 0 1 1 0
1 0 1 1 0 0 0 1 1 1
0 0 0 1 0 0 1 1 1 0
1 0 1 1 1 1 1 1 0 1
1 1 0 1 1 1 1 0 0 1
1 0 0 0 0 1 1 0 1 0
1 1 1 0 0 0 0 0 1 0
1 1 0 1 1 1 0 0 1 1
1 1 1 1 1 1 0 0 1 1
0 0 0 0 0 1 0 0 0 1
위 행렬 M
의 부분행렬을 참조해보자.
함수형: view()
julia> A = view(M, 3:4, :)
2×10 view(::Matrix{Int64}, 3:4, :) with eltype Int64:
0 0 0 1 0 0 1 1 1 0
1 0 1 1 1 1 1 1 0 1
view(A, inds...)
A
의inds...
에 따른view
를 리턴한다.
그러나 이 형태는 일반적으로 코드를 보기 어렵게 만들기 때문에 선호되지 않는다. 다음의 매크로를 사용하면 view
를 사용하면서도 기본적인 줄리아 문법과 큰 차이가 없다.
매크로: @view
julia> B = @view M[3:4,:]
2×10 view(::Matrix{Int64}, 3:4, :) with eltype Int64:
0 0 0 1 0 0 1 1 1 0
1 0 1 1 1 1 1 1 0 1
@view
매크로는 일반적으로 부분배열을 참조하는 맥락의 코드에 view
가 적용된 것처럼 바꿔주는 매크로다.
블럭 전체에 적용: @views
julia> @views begin
C = M[5:6,:];
D = M[7:8,:];
end
2×10 view(::Matrix{Int64}, 7:8, :) with eltype Int64:
1 1 1 0 0 0 0 0 1 0
1 1 0 1 1 1 0 0 1 1
julia> C
2×10 view(::Matrix{Int64}, 5:6, :) with eltype Int64:
1 1 0 1 1 1 1 0 0 1
1 0 0 0 0 1 1 0 1 0
julia> D
2×10 view(::Matrix{Int64}, 7:8, :) with eltype Int64:
1 1 1 0 0 0 0 0 1 0
1 1 0 1 1 1 0 0 1 1
@views
매크로는 @view
를 이어지는 블럭 전체에 적용시켜준다. 이 덕에 view
없이 편하게 작성한 함수 앞에 @views f(x) ... end
처럼 @views
만 붙여주면 알아서 view
를 적용시켜준다.
전체 코드
M = rand(0:1,10,10)
A = view(M, 3:4, :)
B = @view M[3:4,:]
@views begin
C = M[5:6,:];
D = M[7:8,:];
end
C
D
fcopy(x) = sum(x[2:end-1]);
@views fview(x) = sum(x[2:end-1]);
x = rand(10^6);
@time fcopy(x);
@time fview(x);
속도 비교
julia> fcopy(x) = sum(x[2:end-1]);
julia> @views fview(x) = sum(x[2:end-1]);
julia> x = rand(10^6);
julia> @time fcopy(x);
0.015874 seconds (11.08 k allocations: 8.201 MiB, 79.77% compilation time)
julia> @time fview(x);
0.016209 seconds (77.07 k allocations: 4.149 MiB, 96.49% compilation time)
fcopy()
와 fview()
는 정확히 같은 기능을 하는 함수지만 속도에서 차이가 난다. 위 결과만 보면 비슷비슷한 속도처럼 보이지만 대부분은 컴파일 시간compilation Time이다. 이를 제외하고 단순 실행시간만 비교해보면 다음과 같이 약 4배 정도의 차이가 난다.
julia> @time fcopy(x);
0.002933 seconds (3 allocations: 7.629 MiB)
julia> @time fview(x);
0.000660 seconds (1 allocation: 16 bytes)
환경
- OS: Windows
- julia: v1.7.0