Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中高效的哈希映射容器?_Haskell_Hashmap_Hashtable_Unordered Map - Fatal编程技术网

Haskell中高效的哈希映射容器?

Haskell中高效的哈希映射容器?,haskell,hashmap,hashtable,unordered-map,Haskell,Hashmap,Hashtable,Unordered Map,我想使用Haskell计算存储在文件中的唯一块。 该块是长度为512的连续字节,目标文件的大小至少为1GB 这是我的第一次尝试 import Control.Monad import qualified Data.ByteString.Lazy as LB import Data.Foldable import Data.HashMap import Data.Int import qualified Data.Li

我想使用Haskell计算存储在文件中的唯一块。 该块是长度为512的连续字节,目标文件的大小至少为1GB

这是我的第一次尝试

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
我认为这主要是由于hashmap实现,并尝试了其他实现,如
hashmap
hashtables
无序容器
。 但是没有任何明显的区别


请帮助我改进这个程序。

我认为你无法打败python词典的性能。它们实际上是用c实现的,经过多年的优化,另一方面,hashmap是新的,没有太多优化。因此,在我看来,获得3倍的性能就足够了。您可以在某些地方优化haskell代码,但这并不重要。如果您仍然坚持要提高性能,我认为您应该在代码中使用高度优化的c库和ffi

下面是一些类似的讨论


这可能与您的用法完全无关,但我有点担心
插入(+)块1
。如果计数达到高位,则会在哈希映射的单元格中累积thunk。使用只强制脊椎的
($!)
,这并不重要——这些值可能仍然是惰性的

Data.HashMap
没有像
Data.Map
那样提供严格的版本
insertWith'
。但您可以实现它:

insertWith' :: (Hashable k, Ord k) => (a -> a -> a) -> k -> a 
                                   -> HashMap k a -> HashMap k a
insertWith' f k v m = maybe id seq maybeval m'
    where
    (maybeval, m') = insertLookupWithKey (const f) k v m
此外,您可能希望输出(而不是输入)来自
toBlocks
的strict bytestring列表,这将加快散列速度


这就是我所拥有的——不过我不是性能大师。

我通过创建一个
data Blk=Blk{-#UNPACK}字64,可以挤出一点时间
保存512字节。如果您切换到strict ByteString,性能会有相当大的提高,但我不确定这其中有多少是由于缓存之类的影响,还有多少是由于我的老对手懒惰的ByteString块没有合理的对齐(这让我担心,因为它会导致分支、复制等)。最后,
无序容器
做得最好(py为4.8秒,hs为6.5秒,但这是严格的testrings),而
哈希表
由于没有
插入
操作而令人沮丧。@luqui感谢您的回答,我从您那里学到了一些东西。实际上,
无序容器中有
Data.HashMap.Strict
,我试过了,但它不能改善情况,Strict
ByteString也不能
toStrict
有点贵。
toStrict
如果将
defaultChunkSize
更改为
512
的倍数,然后通过TestRing重新编译/安装,可能会有好处。如果不这样做,
toStrict
函数将在几乎每个块边界复制数据。实际上,我最关心的是内存使用情况,我无法理解Haskell hashmaps的内存过度使用。例如,当输入文件仅包含600MB的唯一数据时,它会占用大约1GB或更多的内存。无论如何,谢谢你的回答和文章链接。我应该考虑使用FFI。@昏迷,这只是GHC。GHC垃圾收集策略使用复制收集器,速度非常快,但内存开销是原来的2倍。
insertWith' :: (Hashable k, Ord k) => (a -> a -> a) -> k -> a 
                                   -> HashMap k a -> HashMap k a
insertWith' f k v m = maybe id seq maybeval m'
    where
    (maybeval, m') = insertLookupWithKey (const f) k v m