Hacker Newsnew | past | comments | ask | show | jobs | submit | code51's favoriteslogin

Don't do something that generates thunks in a long-running loop which'll hold references to them. (This applies to JS...virtually any language with GC and first-class functions as well). This is pretty easy to fix and identify once you know what you're doing.

Don't use String. Use Text for Text, ByteString for raw bytes.

Related to String: don't use lists for large datasets unless you're intentionally modeling and reasoning about your data as an infinite space. Use Vector if it's finite, fits in memory, and you're going to comprehend it all at once. Vector gives you cache-friendliness as well.

As a safe default: lazy in the spine, strict in the leaves.

Use streaming libraries (Pipes, Conduit) for processing large datasets. I did a test with a csv parsing library and compared the non-streaming (default) interface and the streaming interface provided by pipes-csv for summing columns in a ~6mb CSV.

No streaming used 30mb of heap.

Naive streaming used 10mb.

Pipes used 600kb.

monad-control and mtl (monad transformer libraries) are pretty fast and can be used without much (any?) worry in 99.999% of circumstances.

Use attoparsec and be mindful of backtracking anytime you're doing perf sensitive parsing. If you hit a limit, you may need to use a parser generator but this is almost never the case. If you need to parse something huge...use a streaming parser.

Sometimes CPS transformation can be a huge boon. Read what Bryan O'Sullivan was written about this for the parsing side of it. Kmett has good examples of CPS transformation for performance in his libraries as well.

Use async.

Default to using TVars (STM containers) for correctness until you know what specific properties you need. If you get perf sensitive but still want transactions, turn the scope of your transactions into cells of a data structure. Cf. http://hackage.haskell.org/package/stm-containers when you have composable concurrency abstractions, it can become just yet another data structures problem.

If you're writing a (very) hot loop, you'll probably end up looking to avoid boxing (just like Java) and touching the heap (just like Java, C, C++). Don Stewart has written good, thorough examples of this.

Resources:

Anything Don Stewart has ever written

Kmett's libraries and blog

Bryan O'Sullivan's libraries (particularly attoparsec and aeson) and blog

Johan Tibell is the strictness perf honcho. Check his libraries for ideas if you're making something strict. Don Stewart has written along these lines too.

http://book.realworldhaskell.org/ is out of date but the stuff on perf and debugging are some of the best in the book.

My own book http://haskellbook.com/ will explain how to reason about performance and laziness, though it's primarily a practical beginner's book. Focus WRT perf will be more on understanding the foundations, how things evaluate, how the runtime works so you can absorb all the other information as easily as possible.

Koalafications:

Every backend I work on in ad tech, including the public facing adserver, is written in Haskell. Our adserver latencies range 12-17ms with some pretty gentle 99th percentiles. The average DSP we talk to has response times in the low hundreds (100-400).


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: