2015-02-21 14 views
10

Tôi có 2 hàm để xác định số pi trong Julia. Hàm thứ hai (mà tôi nghĩ là được vector hóa) là chậm hơn so với hàm đầu tiên. Tại sao vectorization chậm hơn? Có quy tắc nào khi vector hóa và khi nào không?khi vectorization được ưa chuộng ở Julia?

function determine_pi(n) 
    area = zeros(Float64, n); 
    sum = 0; 
    for i=1:n 
     if ((rand()^2+rand()^2) <=1) 
      sum = sum + 1; 
     end 
      area[i] = sum*1.0/i; 
    end 
    return area 
end 

và chức năng khác

function determine_pi_vec(n) 
    res = cumsum(map(x -> x<=1?1:0, rand(n).^2+rand(n).^2))./[1:n] 
    return res 
end 

Khi chạy với n = 10^7, dưới đây là thời gian thực hiện (sau khi chạy vài lần)

n=10^7 
@time returnArray = determine_pi(n) 
#output elapsed time: 0.183211324 seconds (80000128 bytes allocated) 
@time returnArray2 = determine_pi_vec(n); 
#elapsed time: 2.436501454 seconds (880001336 bytes allocated, 30.71% gc time) 

Trả lời

8

bản vẽ Gia là tốt nếu

  • Làm cho mã dễ đọc hơn và hiệu suất không phải là c Nếu nó là một hoạt động đại số tuyến tính, sử dụng một kiểu vectorized có thể là tốt bởi vì Julia có thể sử dụng BLAS và LAPACK để thực hiện thao tác của bạn với mã hiệu năng cao, chuyên biệt rất chuyên nghiệp.

Nói chung, cá nhân tôi tìm thấy nó tốt nhất để bắt đầu với mã vectơ, tìm bất kỳ vấn đề tốc độ nào, sau đó tìm ra bất kỳ vấn đề phiền hà nào.

Mã thứ hai của bạn chậm không nhiều do nó bị vectơ hóa, nhưng do việc sử dụng chức năng ẩn danh: không may trong Julia 0.3, những điều này thường chậm hơn một chút. map nói chung không hoạt động tốt, tôi tin rằng vì Julia không thể suy ra loại đầu ra của hàm (nó vẫn "ẩn danh" từ quan điểm của hàm map). Tôi đã viết một phiên bản vectorized khác nhau mà tránh các chức năng ẩn danh, và có thể là một chút dễ dàng hơn để đọc:

function determine_pi_vec2(n) 
    return cumsum((rand(n).^2 .+ rand(n).^2) .<= 1) ./ (1:n) 
end 

Điểm chuẩn với

function bench(n, f) 
    f(10) 
    srand(1000) 
    @time f(n) 
    srand(1000) 
    @time f(n) 
    srand(1000) 
    @time f(n) 
end 

bench(10^8, determine_pi) 
gc() 
bench(10^8, determine_pi_vec) 
gc() 
bench(10^8, determine_pi_vec2) 

mang lại cho tôi những kết quả

elapsed time: 5.996090409 seconds (800000064 bytes allocated) 
elapsed time: 6.028323688 seconds (800000064 bytes allocated) 
elapsed time: 6.172004807 seconds (800000064 bytes allocated) 
elapsed time: 14.09414031 seconds (8800005224 bytes allocated, 7.69% gc time) 
elapsed time: 14.323797823 seconds (8800001272 bytes allocated, 8.61% gc time) 
elapsed time: 14.048216404 seconds (8800001272 bytes allocated, 8.46% gc time) 
elapsed time: 8.906563284 seconds (5612510776 bytes allocated, 3.21% gc time) 
elapsed time: 8.939001114 seconds (5612506184 bytes allocated, 4.25% gc time) 
elapsed time: 9.028656043 seconds (5612506184 bytes allocated, 4.23% gc time) 

để vector hóa mã chắc chắn có thể được về tốt như devectorized trong một số trường hợp, ngay cả khi chúng tôi không phải là trong một trường hợp đại số tuyến tính.

+0

Cảm ơn. Tôi đã thay đổi mã thứ hai để xóa chức năng ẩn danh nhưng nó vẫn hoạt động kém: chức năng isInside (x) x <= 1? 1: 0 kết thúc; chức năng xác định_pi_vec (n) res = cumsum (bản đồ (isInside, rand (n).^2 + rand (n).^2)) ./ [1: n]; trả lại số kết thúc; @time returnArray2 = define_pi_vec (n); # thời gian trôi qua: 2,303632751 giây (880001336 byte được phân bổ, 31,88% gc thời gian) –

+3

Chức năng ẩn danh không phải là vấn đề lớn nhất - đó là 'map' không có đối số hàm inline và tạo mã chuyên biệt, trong khi bằng cách tránh ánh xạ, kiểm tra isInside có thể được inlined. – StefanKarpinski

+0

Có, tôi vừa cập nhật câu trả lời của mình để cố gắng làm rõ điểm đó – IainDunning

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