Running code in GHCi's interpreter will always be much slower than compiling it to a binary.
Make sure you're compiling your code with ghc.
Are you compiling with -Wall?
GHC warns about type defaults and missing type signatures:
If you let GHC default integers, it will choose Integer. This is
10x slower than
Int. So make sure you explicitly choose your types.
You should have explicit types to not miss something obvious in the
types that is slow.
Are you compiling with -O or above?
By default GHC does not optimize your programs. Cabal and Stack enable
this in the build process. If you're calling ghc directly, don't
forget to add -O.
Enable -O2 for serious, non-dangerous optimizations.
Allocating in GC is claimed to be "fast" but not allocating is always faster.
Have you checked for stack space leaks?
Most space leaks result in an excess use of stack. If you look for the
part of the program that results in the largest stack usage, that is
the most likely space leak, and the one that should be investigated
first.
Benchmarking is a tricky business to get right, especially when timing
things at a smaller scale. Haskell is lucky to have a very good
benchmarking package. If you are asking someone for help, you are
helping them by providing benchmarks, and they are likely to ask for
them.
This GitHub organization provides comparative benchmarks against a few
types of data structures. You can often use this to determine which
data structure is best for your problem:
By default, Haskell fields are lazy and boxed. Making them strict can
often (not always) give them more predictable performance, and unboxed
fields (such as integers) do not require pointer indirection.
This is a suggestion from the HaskellWiki, but I believe it's based on out of date information about how GHC does inlining. It's left here for interested parties, however.
Haskell compiles down to a small language, Core, which represents the
real code generated before assembly. This is where many optimization
passes take place.
An array with boxed elements such as Data.Vector.Vector a means each
element is a pointer to the value, instead of containing the values
inline.
Use an unboxed vector where you can (integers and atomic types like
that) to avoid the pointer indirection. The vector may be stored and
accessed in the CPU cache, avoiding mainline memory altogether.
Likewise, a mutable container like IORef or STRef both contain a
pointer rather than the value. Use URef for an unboxed version.
请发表评论