
Relative speed comparison below Udo Stenzel wrote:
Sebastian Sylvan wrote:
On 1/5/06, Chris Kuklewicz
wrote: There is no need to beat a dead horse, though. This benchmark sets out to test fgets / atoi, and that is all. There are better benchmarks to spend time on.
I agree. The benchmark really is about how fast you can call low-level IO system calls. But since Haskell is a high-level language it's natural that it's a bit difficult to get access to these unsafe (but fast) low-level functions.
There's probably a bit more to it. First off, one could legitimately argue that (liftM lines getContents) is the Haskell way to do line oriented IO. The real question is, why does the fast solution have to be ugly
foreign import ccall "stdio.h" fgets :: CString -> Int -> Ptr CFile ->IO CString foreign import ccall safe "stdlib.h" atoi :: CString -> Int foreign import ccall safe "stdio.h &(*stdin)" c_stdin :: Ptr CFile
and why does the idiomatic solution have to be slow?
| main = print . sum . map read . lines =<< getContents
The biggest hit is probably the construction of a huge String as linked list, which cannot be deforested away (not with the foldr/build mechanism anyway). Assuming we find a better representation for Strings, we could make some headway here and in many other benchmarks.
So I think, just by replacing String and along with it getContents, lines and read, we will get competitive speed and retain the ability to handle arbitrarily long lines. Of course, the shootout wouldn't care for a feature that is otherwise quite important in practice... Anyway, I'll try try to come up with something and then follow up on this.
Udo.
The solution on the wiki (Char by Char) is the fastest I could make :
print . total =<< getContents Time was 1.00 seconds
I tried using getLine and it was slower:
let next rt = do line <- catch getLine (\_ -> return []) if (null line) then return (I# rt) else next (rt +# aLine line) Time was 3.79 seconds
I tried using getContents and lines and it was slowest:
total <- return.(next 0#).lines =<< getContents Time was 4.76 seconds
From this, I assume the buffering that getContents does is very optimized. The cost of getLine was very nontrivial. So for non-binary input, I would recommend using getContents and processing it Char by Char.
-- Chris