Tôi có một chương trình Haskell tạo ra ~ 280M dữ liệu ghi nhật ký trong khi chạy bên trong đơn vị ST. Đây là nơi mà hầu như tất cả bộ nhớ tiêu thụ đi (với đăng nhập bị vô hiệu hóa chương trình phân bổ một tổng số lớn của bộ nhớ thực 3MB).Ghi nhật ký dữ liệu chuỗi hiệu quả trong ST Monad của Haskell
Vấn đề là, tôi hết bộ nhớ. Trong khi chương trình chạy bộ nhớ tiêu thụ vượt quá 1,5 GB, và cuối cùng nó chạy ra khi nó cố gắng để viết chuỗi đăng nhập vào một tập tin.
Chức năng log mất một String và tích lũy các dữ liệu đăng nhập vào một người thợ xây chuỗi lưu trữ trong một STRef trong môi trường:
import qualified Data.ByteString.Lazy.Builder as BB
...
myLogFunction s = do
...
lift $ modifySTRef myStringBuilderRef (<> BB.stringUtf8 s)
Tôi đã cố gắng giới thiệu tính nghiêm minh sử dụng các mẫu tiếng nổ và modifySTRef', nhưng điều này đã tiêu thụ bộ nhớ thậm chí tệ hơn.
tôi viết chuỗi log theo khuyến cáo của các tài liệu hPutBuilder, như thế này:
hSetBinaryMode h True
hSetBuffering h $ BlockBuffering Nothing
BB.hPutBuilder h trace
này tiêu thụ nhiều thêm GBS bộ nhớ. Tôi đã thử các cài đặt đệm khác nhau và chuyển sang một ByteString lười đầu tiên (hơi tốt hơn).
Qs:
Làm thế nào tôi có thể giảm thiểu mức tiêu thụ bộ nhớ khi chương trình chạy? Tôi mong đợi được đưa ra một biểu diễn ByteString chặt chẽ và mức độ nghiêm ngặt thích hợp tôi cần bộ nhớ ít hơn ~ 280M dữ liệu nhật ký thực mà tôi đang lưu trữ.
Làm cách nào để ghi kết quả vào tệp mà không cần cấp phát bộ nhớ? Tôi không hiểu tại sao Haskell cần GB bộ nhớ để chỉ truyền một số dữ liệu cư trú vào một tệp.
Edit:
Dưới đây là hồ sơ cá nhân bộ nhớ cho một hoạt động nhỏ (~ 42MB dữ liệu log). Tổng dung lượng bộ nhớ sử dụng là 3MB với tính năng ghi nhật ký bị tắt.
15,632,058,700 bytes allocated in the heap
4,168,127,708 bytes copied during GC
343,530,916 bytes maximum residency (42 sample(s))
7,149,352 bytes maximum slop
931 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 29975 colls, 0 par 5.96s 6.15s 0.0002s 0.0104s
Gen 1 42 colls, 0 par 6.01s 7.16s 0.1705s 1.5604s
TASKS: 3 (1 bound, 2 peak workers (2 total), using -N1)
SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
INIT time 0.00s ( 0.00s elapsed)
MUT time 32.38s (33.87s elapsed)
GC time 11.97s (13.31s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 0.00s ( 0.00s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 44.35s (47.18s elapsed)
Alloc rate 482,749,347 bytes per MUT second
Productivity 73.0% of total user, 68.6% of total elapsed
Edit:
Tôi chạy một hồ sơ bộ nhớ với một chạy log nhỏ như hỏi:
profile http://imageshack.us/a/img14/9778/6a5o.png
Tôi đã thử thêm tiếng nổ mô hình, $ !, deepseq/$ !!, lực lượng và như vậy ở những nơi có liên quan, nhưng nó dường như không tạo ra bất kỳ sự khác biệt nào. Làm thế nào để tôi buộc Haskell thực sự lấy chuỗi/biểu thức printf của tôi vv và đặt nó trong một ByteString chặt chẽ thay vì giữ tất cả những [Char] danh sách và khối không được đánh giá xung quanh?
Edit:
Dưới đây là những thực tế đầy đủ dấu vết chức năng
trace s = do
enable <- asks envTraceEnable
when (enable) $ do
envtrace <- asks envTrace
let b = B8.pack s
lift $ b `seq` modifySTRef' envtrace (<> BB.byteString b)
Đây có phải là 'nghiêm ngặt' đủ? Tôi có cần phải xem xét cho bất cứ điều gì nếu tôi gọi chức năng này typeclass bên trong đơn vị ReaderT/ST của tôi? Chỉ để nó thực sự được gọi và không được trì hoãn theo bất kỳ cách nào.
do
trace $ printf "%i" myint
không sao?
Cảm ơn!
Việc ghi nhật ký không phải là về nhà nước và do đó tôi sẽ đề nghị bạn sử dụng Writer monad cho nó – Ankur
Thậm chí nếu chuyển đổi từ việc sử dụng một đơn vị đọc với STREF cho một nhà văn tôi có cùng một tình huống. Cuối cùng, nó là một loại Builder. Tôi không muốn thêm một WriterT trong ngăn xếp biến áp vì không có lý do chính đáng. – NBFGRTW
Chúng tôi cần thêm dữ liệu. Bạn có thể cho chúng tôi thấy một hồ sơ heap? Nhật ký của bạn được tạo như thế nào? Nếu bạn sử dụng, ví dụ, 'stringUtf8', thì nghi ngờ của tôi là kết quả' Builder' chứa một số lượng lớn các tham chiếu đến 'Chuỗi', và đó là nơi bộ nhớ đi. –