मैं हास्केल का उपयोग कर फ़ाइल में संग्रहीत अद्वितीय ब्लॉक गिनना चाहता हूं। ब्लॉक 512 की लंबाई के साथ लगातार बाइट्स है और लक्ष्य फ़ाइल का आकार कम से कम 1 जीबी है।हास्केल में कुशल हैश नक्शा कंटेनर?
यह मेरी प्रारंभिक कोशिश है।
import Control.Monad
import qualified Data.ByteString.Lazy as LB
import Data.Foldable
import Data.HashMap
import Data.Int
import qualified Data.List as DL
import System.Environment
type DummyDedupe = Map LB.ByteString Int64
toBlocks :: Int64 -> LB.ByteString -> [LB.ByteString]
toBlocks n bs | LB.null bs = []
| otherwise = let (block, rest) = LB.splitAt n bs
in block : toBlocks n rest
dedupeBlocks :: [LB.ByteString] -> DummyDedupe -> DummyDedupe
dedupeBlocks = flip $ DL.foldl' (\acc block -> insertWith (+) block 1 $! acc)
dedupeFile :: FilePath -> DummyDedupe -> IO DummyDedupe
dedupeFile fp dd = LB.readFile fp >>= return . (`dedupeBlocks` dd) . toBlocks 512
main :: IO()
main = do
dd <- getArgs >>= (`dedupeFile` empty) . head
putStrLn . show . (*512) . size $ dd
putStrLn . show . (*512) . foldl' (+) 0 $ dd
यह काम करता है, लेकिन मैं इसके निष्पादन समय और स्मृति उपयोग से निराश हो गया। स्पष्ट रूप से जब मैंने नीचे सूचीबद्ध सी ++ और यहां तक कि पायथन कार्यान्वयन की तुलना की, तो यह 3 ~ 5x धीमा था और 2 ~ 3x अधिक स्मृति स्थान का उपभोग किया।
import os
import os.path
import sys
def dedupeFile(dd, fp):
fd = os.open(fp, os.O_RDONLY)
for block in iter(lambda : os.read(fd, 512), ''):
dd.setdefault(block, 0)
dd[block] = dd[block] + 1
os.close(fd)
return dd
dd = {}
dedupeFile(dd, sys.argv[1])
print(len(dd) * 512)
print(sum(dd.values()) * 512)
मैंने सोचा कि यह मुख्य रूप से hashmap कार्यान्वयन की वजह से था, और इस तरह hashmap
, hashtables
और unordered-containers
के रूप में अन्य कार्यान्वयन की कोशिश की। लेकिन कोई ध्यान देने योग्य अंतर नहीं था।
कृपया इस कार्यक्रम को बेहतर बनाने में मेरी सहायता करें।
असल में, जो मुझे सबसे ज्यादा ख्याल है वह मेमोरी उपयोग है, मैं हास्केल हैशैप्स के अत्यधिक मेमोरी उपयोग को समझ नहीं पा रहा हूं। जैसे जब इनपुट फ़ाइल में केवल 600 एमबी अद्वितीय डेटा होता है, तो यह लगभग 1 जीबी मेमोरी या अधिक का उपयोग करता है। वैसे भी, आपके उत्तर और आलेख लिंक के लिए धन्यवाद। मुझे एफएफआई का उपयोग करने पर विचार करना चाहिए। – comatose
@comatose, यह सिर्फ जीएचसी है। जीएचसी कचरा संग्रहण रणनीति एक प्रतिलिपि कलेक्टर का उपयोग करती है, जो वास्तव में तेज़ है, लेकिन इसमें 2x मेमोरी ओवरहेड है। – luqui