2014-12-28 12 views
7

Tôi nghĩ rằng trong Julia (không giống như trong R hoặc Matlab) mã devectorized thường nhanh hơn mã vectơ. Nhưng tôi không tìm thấy điều này. Dưới đây là ví dụ:Tại sao mã Julia bị bỏ qua này quá 20x quá chậm?

julia> x = Float64[1:10000000]; 

julia> y = Array(Float64, length(x)); 

julia> @time for i = 1:length(x) y[i] = exp(x[i]) end; 
elapsed time: 7.014107314 seconds (959983704 bytes allocated, 25.39% gc time) 

julia> @time y = exp(x); 
elapsed time: 0.364695612 seconds (80000128 bytes allocated) 

Tại sao mã vectơ lại nhanh hơn rất nhiều? Có vẻ như mã được phân chia sẽ phân bổ trên 10 lần bộ nhớ. Nhưng chỉ có một vài byte thực sự cần phải được phân bổ để exponentiate bất kỳ số lượng nổi. Có cách nào để viết mã devectorized để nó không phân bổ rất nhiều bộ nhớ, và do đó chạy nhanh hơn mã vectơ?

Cảm ơn!

+0

"_I nghĩ ..._" Bạn nên luôn cung cấp một số bằng chứng để hỗ trợ các tuyên bố về bản chất này. – csmckelvey

+2

Chắc chắn, đây là bài đăng thể hiện mã có thể bị phân tách nhanh hơn bao nhiêu trong Julia: http://www.johnmyleswhite.com/notebook/2013/12/22/the-relationship-between-vectorized-and-devectorized-code/ – Jeff

Trả lời

10

Hãy xem xét các đoạn mã sau:

x = Float64[1:10000000]; 
y = Array(Float64, length(x)); 
function nonglobal_devec!(x,y) 
    for i = 1:length(x) y[i] = exp(x[i]) end 
end 
function nonglobal_vec(x) 
    exp(x) 
end 
@time nonglobal_devec!(x,y); 
@time y = nonglobal_vec(x); 
x = Float64[1:10000000]; 
y = Array(Float64, length(x)); 
@time for i = 1:length(x) y[i] = exp(x[i]) end 
@time y = exp(x) 

mang đến cho các lần

A: elapsed time: 0.072701108 seconds (115508 bytes allocated) 
B: elapsed time: 0.074584697 seconds (80201532 bytes allocated) 
C: elapsed time: 2.029597656 seconds (959990464 bytes allocated, 22.86% gc time) 
D: elapsed time: 0.058509661 seconds (80000128 bytes allocated) 

Một lẻ ra, C, là due to it operating in the global scope, trong đó kiểu suy luận không hoạt động và s mã thấp hơn được tạo.

Thời gian tương đối giữa A và B có thể thay đổi do các hàm được biên dịch lần đầu tiên chúng được sử dụng. Nếu chúng ta chạy nó một lần nữa chúng tôi nhận

A2: elapsed time: 0.038542212 seconds (80 bytes allocated) 
B2: elapsed time: 0.063630172 seconds (80000128 bytes allocated) 

có ý nghĩa như A2 không phân bổ bộ nhớ (80 byte là cho giá trị trả về của hàm), và B2 sẽ tạo ra một vector mới. Cũng lưu ý rằng B2 phân bổ cùng một lượng bộ nhớ như D - lần đầu tiên được cấp phát bộ nhớ để biên dịch.

Cuối cùng, được phân tách và được vectơ hóa là trường hợp từng trường hợp cụ thể. Ví dụ, nếu bạn đã thực hiện phép nhân bản ma trận một cách ngây thơ với các vòng lặp và không có nhận thức về bộ nhớ cache, bạn sẽ có khả năng chậm hơn nhiều so với sử dụng véc tơ A*b sử dụng BLAS.

+2

Cảm ơn, Iain, đó là một câu trả lời tốt hơn nhiều so với tôi. – StefanKarpinski

+0

Tôi sẽ cướp chủ đề này một chút để hỏi nếu 80 byte trong A2 được phân bổ mỗi lần chức năng được gọi? Ví dụ, nếu hàm đó trong một vòng lặp for gọi nó là 10^5 lần, thì 80 * 10^5 byte có được cấp phát không? – Nick

+0

Khá chắc chắn nó sẽ không, mà là dễ dàng để kiểm tra - nó chỉ là một điều REPL. Những điều kỳ lạ ở REPL mặc dù! Nếu bạn đã đặt lệnh đó trong một vòng lặp, tại REPL, tôi nghĩ bạn có thể nhận được 80 byte, đó sẽ là giá trị từ lần cuối cùng quanh vòng lặp. – IainDunning

Các vấn đề liên quan