2016-01-27 22 views
5

Tôi đã xem xét các tùy chọn hiện tại cho regex trong Haskell và tôi muốn hiểu khoảng cách về hiệu suất đến từ đâu khi so sánh các tùy chọn khác nhau và đặc biệt với một lệnh gọi đơn giản là grep .. .Hiệu suất của Haskell Regex

tôi có một tương đối nhỏ (~ 110 triệu, so với bình thường nhiều 10s của G trong hầu hết các trường hợp sử dụng của tôi) trace file:

$ du radixtracefile 
113120 radixtracefile 
$ wc -l radixtracefile 
1051565 radixtracefile 

  • lần đầu tiên tôi đã cố gắng để tìm cách nhiều trận đấu của (tùy ý) mẫu .*504.*ll là trong đó thông qua grep:
$ time grep -nE ".*504.*ll" radixtracefile | wc -l 
309 

real 0m0.211s 
user 0m0.202s 
sys 0m0.010s 

  • Tôi nhìn Text.Regex.TDFA (phiên bản 1.2.1) với Data.ByteString:
import Control.Monad.Loops 
import Data.Maybe 
import qualified Data.Text as T 
import qualified Data.Text.IO as TIO 
import Text.Regex.TDFA 
import qualified Data.ByteString as B 

main = do 
    f <- B.readFile "radixtracefile" 
    matches :: [[B.ByteString]] <- f =~~ ".*504.*ll" 
    mapM_ (putStrLn . show . head) matches 

Xây dựng và chạy:

$ ghc -O2 test-TDFA.hs -XScopedTypeVariables 
[1 of 1] Compiling Main    (test-TDFA.hs, test-TDFA.o) 
Linking test-TDFA ... 
$ time ./test-TDFA | wc -l 
309 

real 0m4.463s 
user 0m4.431s 
sys 0m0.036s 

  • Sau đó, tôi nhìn vào Data.Text.ICU.Regex (phiên bản 0.7.0.1) với sự hỗ trợ Unicode:
import Control.Monad.Loops 
import qualified Data.Text as T 
import qualified Data.Text.IO as TIO 
import Data.Text.ICU.Regex 

main = do 
    re <- regex [] $ T.pack ".*504.*ll" 
    f <- TIO.readFile "radixtracefile" 
    setText re f 
    whileM_ (findNext re) $ do 
     a <- start re 0 
     putStrLn $ "last match at :"++(show a) 

Xây dựng và chạy:

$ ghc -O2 test-ICU.hs 
[1 of 1] Compiling Main    (test-ICU.hs, test-ICU.o) 
Linking test-ICU ... 
$ time ./test-ICU | wc -l 
309 

real 1m36.407s 
user 1m36.090s 
sys 0m0.169s 

Tôi sử dụng phiên bản 7.6.3. Tôi đã không có dịp thử nghiệm các tùy chọn regex Haskell khác. Tôi biết rằng tôi sẽ không nhận được hiệu suất mà tôi đã có với grep và đã được hạnh phúc hơn với điều đó, nhưng nhiều hơn hoặc ít hơn 20 lần chậm hơn cho TDFA và ByteString ... Điều đó là rất đáng sợ. Và tôi không thể thực sự hiểu tại sao nó là những gì nó được, như tôi ngây thơ mặc dù rằng đây là một wrapper trên một phụ trợ bản địa ... Tôi bằng cách nào đó không sử dụng các mô-đun một cách chính xác?

(Và chúng ta không đề cập đến ICU + chữ kết hợp mà đang trải qua mái nhà)

Có một lựa chọn mà tôi đã không kiểm tra được nêu ra mà có thể làm tôi hạnh phúc hơn?

EDIT:

  • Text.Regex.PCRE (phiên bản 0.94.4) với Data.ByteString:
import Control.Monad.Loops 
import Data.Maybe 
import Text.Regex.PCRE 
import qualified Data.ByteString as B 

main = do 
    f <- B.readFile "radixtracefile" 
    matches :: [[B.ByteString]] <- f =~~ ".*504.*ll" 
    mapM_ (putStrLn . show . head) matches 

Xây dựng và chạy:

$ ghc -O2 test-PCRE.hs -XScopedTypeVariables 
[1 of 1] Compiling Main    (test-PCRE.hs, test-PCRE.o) 
Linking test-PCRE ... 
$ time ./test-PCRE | wc -l 
309 

real 0m1.442s 
user 0m1.412s 
sys 0m0.031s 

Tốt hơn, nhưng vẫn với một yếu tố ~ 7-ish ...

+0

Bạn đang nói về cách thực hiện chính xác của Haskell? Điều đó có thể tạo nên sự khác biệt. – vonbrand

+0

@vonbrand: Đoạn trích đề cập đến 'ghc -O2'. Liệu vấn đề phiên bản (trình biên dịch/thư viện), hay bạn muốn biết điều gì? – Bergi

+0

@vonbrand: '$ ghc --version' cung cấp cho' Hệ thống biên dịch Glorious Glasgow Haskell, phiên bản 7.6.3'. 'danh sách cabex regex-tdfa' cho (trong số những thứ khác)' regex-tdfa [...] Phiên bản cài đặt: 1.2.1', và 'cabal list text-icu',' text-icu [...] Phiên bản cài đặt : 0,7.0.1'. Đó có phải là thông tin bạn đang tìm kiếm không? Tôi sẽ chỉnh sửa câu hỏi của mình để thêm thông tin này. – gameboo

Trả lời

1

Vì vậy, sau khi xem các thư viện khác một chút, tôi đã kết thúc thử PCRE.Ligth (phiên bản 0.4.0.4):

import Control.Monad 
import Text.Regex.PCRE.Light 
import qualified Data.ByteString.Char8 as B 

main = do 
    f <- B.readFile "radixtracefile" 
    let lines = B.split '\n' f 
    let re = compile (B.pack ".*504.*ll") [] 
    forM_ lines $ \l -> maybe (return()) print $ match re l [] 

Đây là những gì tôi nhận ra điều đó:

$ ghc -O2 test-PCRELight.hs -XScopedTypeVariables 
[1 of 1] Compiling Main    (test-PCRELight.hs, test-PCRELight.o) 
Linking test-PCRELight ... 
$ time ./test-PCRELight | wc -l 
309 

real 0m0.832s 
user 0m0.803s 
sys 0m0.027s 

Tôi nghĩ rằng đây là khá đủ cho mục đích của tôi. Tôi có thể cố gắng để xem những gì xảy ra với các libs khác khi tôi tự làm các dòng tách như tôi đã làm ở đây, mặc dù tôi nghi ngờ nó sẽ tạo ra một sự khác biệt lớn.