Tôi đang cố gắng song song hóa một bộ dò tia. Điều này có nghĩa là tôi có một danh sách rất dài các phép tính nhỏ. Chương trình vani chạy trên một cảnh cụ thể trong 67,98 giây và 13 MB tổng bộ nhớ sử dụng và 99,2% năng suất.
Trong lần thử đầu tiên, tôi đã sử dụng chiến lược song song parBuffer
với kích thước bộ đệm là 50. Tôi đã chọn parBuffer
vì nó lướt qua danh sách chỉ nhanh như tia lửa được tiêu thụ và không ép cột của danh sách parList
, điều này sẽ sử dụng nhiều bộ nhớ vì danh sách rất dài. Với -N2
, nó chạy trong thời gian 100,46 giây và 14 MB tổng bộ nhớ sử dụng và 97,8% năng suất. Thông tin tia lửa là:SPARKS: 480000 (476469 converted, 0 overflowed, 0 dud, 161 GC'd, 3370 fizzled)
Tỷ lệ lớn các tia lửa bị bắn ra cho thấy mức độ chi tiết của các tia lửa quá nhỏ, vì vậy tiếp theo tôi đã thử sử dụng chiến lược parListChunk
chia danh sách thành nhiều phần và tạo ra tia lửa cho mỗi phần. Tôi đã nhận được kết quả tốt nhất với kích thước một đoạn là 0.25 * imageWidth
. Chương trình chạy trong 93,43 giây và 236 MB tổng bộ nhớ sử dụng và 97,3% năng suất. Thông tin spark là: SPARKS: 2400 (2400 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
. Tôi tin rằng việc sử dụng trí nhớ lớn hơn nhiều là bởi vì nó tạo parListChunk
nên cột sống của danh sách.
Sau đó, tôi cố gắng viết chiến lược của riêng mình để chia danh sách thành nhiều phần một cách lười biếng và sau đó chuyển các phần đến parBuffer
và nối kết quả.
concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map colorPixel pixels))
Điều này chạy trong 95,99 giây và 22MB tổng sử dụng bộ nhớ và 98,8% năng suất. Điều này thành công vì tất cả các tia lửa đang được chuyển đổi và việc sử dụng bộ nhớ thấp hơn nhiều, tuy nhiên tốc độ không được cải thiện. Đây là hình ảnh một phần của hồ sơ sự kiện.
Như bạn có thể thấy các luồng đang bị dừng do tràn đống. Tôi đã thử thêm +RTS -M1G
để tăng kích thước heap mặc định lên đến 1Gb. Kết quả không thay đổi. Tôi đọc rằng luồng chính của Haskell sẽ sử dụng bộ nhớ từ heap nếu ngăn xếp của nó bị tràn, vì vậy tôi cũng đã thử tăng kích thước ngăn xếp mặc định +RTS -M1G -K1G
nhưng điều này cũng không có tác động.
Có điều gì khác tôi có thể thử không? Tôi có thể đăng thông tin hồ sơ chi tiết hơn về việc sử dụng bộ nhớ hoặc nhật ký sự kiện nếu cần, tôi không bao gồm tất cả vì đó là rất nhiều thông tin và tôi không nghĩ rằng tất cả cần phải bao gồm.
CHỈNH SỬA: Tôi đã đọc về hỗ trợ đa lõi Haskell RTS và nó nói về việc có một HEC (Haskell Execution Context) cho mỗi lõi. Mỗi HEC chứa, trong số những thứ khác, một Khu vực phân bổ (là một phần của một đống được chia sẻ duy nhất). Bất cứ khi nào hết Khu vực Phân bổ của HEC, việc thu gom rác phải được thực hiện. Dường như là một tùy chọn RTS để kiểm soát nó, -A. Tôi đã thử -A32M nhưng không thấy sự khác biệt.
EDIT2: Đây là một liên kết đến một repo github dành riêng cho câu hỏi này . Tôi đã bao gồm các kết quả hồ sơ trong thư mục hồ sơ.
EDIT3: Đây là đoạn mã liên quan:
render :: [([(Float,Float)],[(Float,Float)])] -> World -> [Color]
render grids world = cs where
ps = [ (i,j) | j <- reverse [0..wImgHt world - 1] , i <- [0..wImgWd world - 1] ]
cs = map (colorPixel world) (zip ps grids)
--cs = withStrategy (parListChunk (round (wImgWd world)) rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = withStrategy (parBuffer 16 rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map (colorPixel world) (zip ps grids)))
Các lưới là các phao ngẫu nhiên được colorPixel tính toán trước và sử dụng. Loại colorPixel
là:
colorPixel :: World -> ((Float,Float),([(Float,Float)],[(Float,Float)])) -> Color
Strategy
. Nên chọn một từ tốt hơn. Ngoài ra, các vấn đề tràn heap xảy ra với parListChunk
và parBuffer
quá.
concat $ withStrategy …
không? Tôi không thể tái tạo hành vi này6008010
, đó là cam kết gần nhất với bản chỉnh sửa của bạn.