我想打印一个用空格分隔的积分列表到stdout。列表生成很快,所以我尝试用序列[1..200000]来解决这个问题。
在C中,我可以像这样实现它:
#include "stdio.h"
int main()
{
int i;
for(i = 0; i <= 200000; ++i)
printf("%d ", i);
return 0;
}
我可以实现的Haskell中最快的解决方案慢了三倍:
import Data.List (intercalate)
main = putStr . intercalate " " . map (show) $ [1..(200000)]
我在某些方面尝试了ByteStrings,但是对它们来说它变得更慢了。 最大的问题似乎是将整数转换为带有show的字符串(或转换为ByteStrings)。
如何在不与C接口的情况下加快速度的建议?它不应该变得复杂(尽可能短而美观,使用其他Haskell模块就可以了)。
答案 0 :(得分:4)
好吧,你可以稍微改写一下代码:
import Data.List (intercalate)
main = output
output = putStr one_string
one_string = intercalate " " strings
strings = map show $ [1..2000000]
然后你可以用“ghc -O2 -prof -auto-all .hs”来描述它:
COST CENTRE MODULE %time %alloc
one_string Main 42.2 55.9
strings Main 39.2 43.1
output Main 18.6 1.0
您可以看到插入占用了运行时的一半。我不认为你可以让整个事情变得更快,但不会诉诸一些低级别的诡计。如果你切换到更快的插入(例如,从Data.ByteString.Lazy.Char8),你将不得不使用较慢的Int - &gt;变体。字符串转换。
答案 1 :(得分:2)
如果我使用ghc-6.10.4而不是ghc-6.12.1,这个程序运行得更快。 IIRC 6.12系列引入了unicode感知IO,我认为这会导致很多放缓。
我的系统:
C (gcc -O2): 0.141s
HS (ghc-6.10.4 -O2): 0.191s (ave.)
HS (ghc-6.12.1 -O2): 0.303 (ave.)
使用ghc-6.10时,结果与C相当;我认为存在差异是由于Haskell使用字符串(也可能是运行时开销)。
如果你想从该编译器获得更好的性能,我认为可以绕过ghc-6.12的I / O中的unicode转换。
答案 2 :(得分:1)
第一个问题:
发布一些代码!!!
我猜(根据delnan :),它很慢,因为发生以下情况(如果你不使用bytestring,则跳过步骤4):
pack
)使用bytestring可能会更快,但您应该实现自己的show
,它可以使用字节串。然后,如此聪明并避免多次转换,在创建列表后输入空格。
也许是这样的:
import qualified Data.Bytestring.Lazy.Char8 as B
showB :: Int -> Bytestring -- Left as an exercise to the reader
main = B.putStr $ pipeline [0..20000] where
pipeline = B.tail . B.concat . map (B.cons' ' ') . map showB
这是未经测试的,所以个人资料!你看,to maps可以融合,所以列表可能会被遍历两次。
答案 3 :(得分:0)
这是针对同一问题的不同方法,尝试利用字符串后缀中的共享。它在我的机器上比原来的Haskell快了约1/3,尽管它仍然远离C版本。执行1到999999之外的数字作为练习:
basic :: [Char]
basic = ['0'..'9']
strip :: String -> String
strip = (' ' :) . dropWhile (== '0')
numbers :: Int -> [String]
numbers 0 = [""]
numbers n = [x : xs | x <- basic, xs <- rest]
where
rest = numbers (n - 1)
main = mapM_ (putStr . strip) (tail $ numbers 6)
答案 4 :(得分:0)
这个版本比你的好一点。我想这是改善它的一种方法。
showWithSpaces :: (Show a) => [a] -> ShowS
showWithSpaces [] = showString ""
showWithSpaces (x:xs) = shows x . showChar ' ' . showWithSpaces xs
main = putStrLn $ showWithSpaces [1..2000000] $ ""