2012-07-03 36 views
7

Vì vậy, tôi có khoảng 8MB tệp của mỗi tệp có 6 int được phân cách bằng dấu cách.Haskell Cách hiệu quả hơn để phân tích cú pháp tệp của các dòng chữ số

phương pháp hiện tại của tôi đối với phân tích này là:

tuplify6 :: [a] -> (a, a, a, a, a, a) 
tuplify6 [l, m, n, o, p, q] = (l, m, n, o, p, q) 

toInts :: String -> (Int, Int, Int, Int, Int, Int) 
toInts line = 
     tuplify6 $ map read stringNumbers 
     where stringNumbers = split " " line 

và toInts lập bản đồ trên

liftM lines . readFile 

mà sẽ trả cho tôi một danh sách các hàng. Tuy nhiên, khi tôi chạy ứng dụng này, sẽ mất gần 25 giây để tải tệp và phân tích cú pháp. Bất kỳ cách nào tôi có thể tăng tốc độ này lên? Tệp chỉ là văn bản thuần túy.

+0

bạn có thể cung cấp thêm một chút thông tin: toàn bộ chương trình làm việc, đầu vào, cách bạn chạy nó, bạn có biên dịch nó (với tối ưu hóa) hay chạy nó trong 'ghci'. Bạn có biết về 'Data.Bytestring' và' Data.Vector'. Ngoài ra 'đọc' là khá chậm, ít nhất đó là những gì tôi đã nghe. – epsilonhalbe

+0

Xem thêm http://stackoverflow.com/questions/8366093/how-do-i-parse-a-matrix-of-integers-in-haskell/8366642 –

Trả lời

8

Bạn có thể tăng tốc độ bằng cách sử dụng ByteString s, ví dụ:

module Main (main) where 

import System.Environment (getArgs) 
import qualified Data.ByteString.Lazy.Char8 as C 
import Data.Char 

main :: IO() 
main = do 
    args <- getArgs 
    mapM_ doFile args 

doFile :: FilePath -> IO() 
doFile file = do 
    bs <- C.readFile file 
    let tups = buildTups 0 [] $ C.dropWhile (not . isDigit) bs 
    print (length tups) 

buildTups :: Int -> [Int] -> C.ByteString -> [(Int,Int,Int,Int,Int,Int)] 
buildTups 6 acc bs = tuplify6 acc : buildTups 0 [] bs 
buildTups k acc bs 
    | C.null bs = if k == 0 then [] else error ("Bad file format " ++ show k) 
    | otherwise = case C.readInt bs of 
        Just (i,rm) -> buildTups (k+1) (i:acc) $ C.dropWhile (not . isDigit) rm 
        Nothing -> error ("No Int found: " ++ show (C.take 100 bs)) 

tuplify6:: [a] -> (a, a, a, a, a, a) 
tuplify6 [l, m, n, o, p, q] = (l, m, n, o, p, q) 

chạy khá nhanh:

$ time ./fileParse IntList 
200000 

real 0m0.119s 
user 0m0.115s 
sys  0m0.003s 

cho một tập tin 8.1 MiB.

Mặt khác, sử dụng String s và chuyển đổi của bạn (với một số seq s để đánh giá) cũng chỉ mất 0,66 giây, vì vậy phần lớn thời gian dường như không được phân tích cú pháp, nhưng làm việc với kết quả.

Rất tiếc, đã bỏ lỡ seq do đó, read không được đánh giá thực sự cho phiên bản String. Sửa rằng, String + read mất khoảng bốn giây, một chút trên một với phân tích cú pháp tùy chỉnh Int từ @ bình luận Rotsor của

foldl' (\a c -> 10*a + fromEnum c - fromEnum '0') 0 

để phân tích rõ ràng đã làm mất một số lượng đáng kể thời gian.

+0

Cảm ơn. Tôi quên về đánh giá Lazy haskell vì vậy tôi đã sai về vấn đề thời gian đến từ đâu. Nhưng cảm ơn cho phương pháp khác cũng! – DantheMan

+0

Bạn có thể vui lòng hiển thị toàn bộ chương trình đạt được 0,66s với 'read' không? Tôi đã [hỏi một câu hỏi tương tự] (http://stackoverflow.com/questions/7510078/why-is-char-based-input-so-much-slower-than-the-char-based-output-in- haskell) trước và câu trả lời là "đọc chậm". Ở đây, chỉ thay thế 'read' bằng' foldl (\ a c -> a * 10 + fromEnum c - fromEnum '0') 0' cho tốc độ cải tiến gấp 6 lần, cho thấy rằng hầu hết thời gian thực sự được phân tích cú pháp. Làm thế nào bạn quản lý để cải thiện về điều đó? – Rotsor

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