高效输出数字
我想打印一个积分列表,用空格分隔到stdout。列表生成速度很快,所以我试图用序列[1..200000]来解决这个问题。高效输出数字
在C,我可以这样实现:
#include "stdio.h"
int main()
{
int i;
for(i = 0; i <= 200000; ++i)
printf("%d ", i);
return 0;
}
在Haskell我可以实现最快的解决方案约3倍慢:
import Data.List (intercalate)
main = putStr . intercalate " " . map (show) $ [1..(200000)]
我想在某些方面字节串,但与他们相比,它变得更慢。 大问题似乎是用show(或转换为ByteStrings)将整数转换为字符串。
任何建议如何加快这一点,而无需连接到C?它不应该变得复杂(尽可能简短和美观,使用其他Haskell模块也可以)。
第一个问题:
Post some code !!!
我猜(根据delnan :),这是因为以下情况的速度慢(跳过步骤4如果你不使用的字节字符串):
- 所有的数字都是一个接一个转换。输出是一个列表。
- 的产出清单已经再次因为你添加元素走过(空格!)
- 名单已经因为你Concat的它
- 名单必须再次经过再次穿越,因为它被转换为字节串(
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
这是未经测试,所以轮廓!你看,地图可以融合,所以列表将被遍历两次。
嗯,你可以重写代码位:
COST CENTRE MODULE %time %alloc
one_string Main 42.2 55.9
strings Main 39.2 43.1
output Main 18.6 1.0
您可以:
import Data.List (intercalate)
main = output
output = putStr one_string
one_string = intercalate " " strings
strings = map show $ [1..2000000]
然后,你可以使用 “GHC -02 -prof - 自动所有杂项文件” 简介它请参阅intercalate占用运行时的一半。尽管如此,我并不认为你可以让整个事情变得更快,但不会诉诸一些低级别的诡计。如果切换到更快插入(例如,来自Data.ByteString.Lazy.Char8),则必须使用Int - > String转换的较慢变体。
下面是针对同一问题的另一种方法,即尝试利用字符串后缀中的共享。它在我的机器上运行速度比原来的Haskell快三分之一左右,尽管毫无疑问仍然是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)
这个程序运行得更快,如果我用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的结果是相当媲美℃;我认为这种差异是由于Haskell使用字符串(也可能是运行时开销)造成的。
我认为如果你想从编译器中获得更好的性能,可以绕过ghc-6.12的I/O中的unicode转换。
这个版本比你的更好一些。我想这是改善它的一种方法。
showWithSpaces :: (Show a) => [a] -> ShowS
showWithSpaces [] = showString ""
showWithSpaces (x:xs) = shows x . showChar ' ' . showWithSpaces xs
main = putStrLn $ showWithSpaces [1..2000000] $ ""
一如既往,分析>>>>>猜测。 – delnan 2010-11-26 13:47:45
您是否检查过每次写入元素的速度?写入控制台通常很慢,所以这可能会更糟糕,但它可能值得一试。您可以尝试构建一定数量的元素而不是一个巨大的字符串,但是您可能需要使用append(++)或Hughes列表(DList)来执行此操作,这会添加额外的工作。这就是为什么我猜测写每个元素仍然有竞争力。 – 2010-11-26 16:17:51
我试过一次写了一个数字的版本(就像我认为的一样),但速度较慢。 – 2010-11-26 16:24:58