Vì vậy, tôi đang viết một ứng dụng sniffing gói. Về cơ bản tôi muốn nó để sniff cho phiên tcp, và sau đó phân tích chúng để xem nếu họ là http, và nếu họ đang có, và nếu họ có loại nội dung đúng, vv, lưu chúng như là một tập tin trên ổ cứng của tôi.Attoparsec phân bổ một tấn bộ nhớ trên 'take' lớn gọi
Vì vậy, để kết thúc, tôi muốn nó có hiệu quả. Vì thư viện http hiện tại là chuỗi dựa trên, và tôi sẽ xử lý các tệp lớn, và tôi chỉ thực sự cần phân tích các câu trả lời http, tôi đã quyết định cuộn thư của mình trong attoparsec.
Khi tôi hoàn thành chương trình, tôi thấy rằng khi tôi phân tích cú pháp phản hồi 9 meg http với tệp wav trong đó, khi tôi định dạng nó, nó đã phân bổ một bộ nhớ khi nó cố phân tích cơ thể của phản hồi http. Khi tôi nhìn vào HTTP.prof tôi thấy một số dòng:
httpBody Main 362 1 0.0 0.0 93.8 99.3 take Data.Attoparsec.Internal 366 1201 0.0 0.0 93.8 99.3 takeWith Data.Attoparsec.Internal 367 3603 0.0 0.0 93.8 99.3 demandInput Data.Attoparsec.Internal 375 293 0.0 0.0 93.8 99.2 prompt Data.Attoparsec.Internal 378 293 0.0 0.0 93.8 99.2 +++ Data.Attoparsec.Internal 380 586 93.8 99.2 93.8 99.2
Như bạn có thể thấy, ở đâu đó trong vòng httpbody, lấy được gọi là 1201 lần, khiến 500 + (+++) concatenations của bytestrings, gây một lượng cấp phát bộ nhớ vô lý.
Đây là mã. N chỉ là độ dài nội dung của câu trả lời http, nếu có. Nếu không có nó chỉ là cố gắng để có tất cả mọi thứ.
Tôi muốn nó trả về giá trị 1000 hoặc nhiều ký tự, nhưng ngay cả khi tôi thay đổi nó để chỉ lấy n và trả về một cách nghiêm ngặt, nó vẫn có những phân bổ trong đó (và nó sử dụng 14 gig bộ nhớ).
httpBody n = do
x <- if n > 0
then AC.take n
else AC.takeWhile (\_ -> True)
if B.length x == 0
then return Nothing
else return (Just x)
Tôi đã đọc blog của anh chàng đã phối hợp và anh ấy gặp vấn đề tương tự nhưng tôi chưa bao giờ nghe nói về giải pháp. Có ai từng gặp vấn đề này trước hoặc tìm ra giải pháp không?
Chỉnh sửa: Được rồi, tôi đã bỏ qua toàn bộ ngày này và không nhận được gì. Sau khi nghiên cứu vấn đề này tôi không nghĩ rằng có một cách để làm điều đó mà không cần thêm một người lười biếng bytestring accessor để attoparsec. Tôi cũng đã xem xét tất cả các thư viện khác và họ thiếu những thứ khác hoặc những thứ khác.
Vì vậy, tôi đã tìm thấy giải pháp thay thế. Nếu bạn nghĩ về một yêu cầu http, nó sẽ đi tiêu đề, dòng mới, dòng mới, nội dung. Vì cơ thể là cuối cùng, và phân tích trả về một tuple với cả những gì bạn phân tích và những gì còn lại của bytestring, tôi có thể bỏ qua phân tích cơ thể bên trong attoparsec và thay vì nhổ cơ thể thẳng offtestring đó là trái.
parseHTTPs bs = if P.length results == 0
then Nothing
else Just results
where results = foldParse(bs, [])
foldParse (bs,rs) = case ACL.parse httpResponse bs of
ACL.Done rest r -> addBody (rest,rs) r
otherwise -> rs
addBody (rest,rs) http = foldParse (rest', rs')
where
contentlength = ((read . BU.toString) (maybe "0" id (hdrContentLength (rspHeaders http))))
rest' = BL.drop contentlength rest
rs' = rs ++ [http { rspBody = body' }]
body'
| contentlength == 0 = Just rest
| BL.length rest == 0 = Nothing
| otherwise = Just (BL.take contentlength rest)
httpResponse = do
(code, desc) <- statusLine
hdrs <- many header
endOfLine
-- body <- httpBody ((read . BU.toString) (maybe "0" id (hdrContentLength parsedHeaders)))
return Response { rspCode = code, rspReason = desc, rspHeaders = parseHeaders hdrs, rspBody = undefined }
Đó là một chút lộn xộn, nhưng cuối cùng nó hoạt động nhanh và phân bổ không có gì nhiều hơn tôi muốn. Vì vậy, về cơ bản bạn gấp qua việc thu thập các cấu trúc dữ liệu http, sau đó ở giữa các bộ sưu tập, tôi kiểm tra độ dài nội dung của cấu trúc mà tôi vừa nhận được, kéo một số tiền thích hợp từ phần còn lại, và sau đó tiếp tục nếu có bất kỳ dấu nào bên trái.
Chỉnh sửa: Tôi thực sự đã hoàn thành dự án này. Làm việc như một say mê. Tôi không được cabalized đúng cách nhưng nếu ai đó muốn xem toàn bộ nguồn, bạn có thể tìm thấy nó tại https://github.com/onmach/Audio-Sniffer.
AC là gì? (filler) –
Có sử dụng [hoạt động chống phân mảnh của nhà xây dựng blaze] (http://lambda-view.blogspot.com/2010/11/defragmenting-lazy-bytestrings.html) khắc phục vấn đề này không? –
AC đủ điều kiện để nhập dữ liệu.Attoparsec.Char8 –