liveBook · Manning

Spark pool

As explained in Learn Haskell by Example

A spark pool is the runtime-managed collection of pending sparks awaiting available parallel execution capacity.

A spark pool is the runtime-managed holding area for sparks: pointers to unevaluated thunks that may be evaluated in parallel. Creating a spark does not itself evaluate the thunk; it makes parallel work available to the runtime. section 13.4.3

Haskell execution contexts (HECs), roughly runtime-managed operating-system threads, take available sparks from a pool through work stealing. An idle HEC can steal a spark and evaluate its thunk, while the runtime handles scheduling and related cleanup details. section 13.4.3

Figure 13.5 Haskell execution contexts and spark pools
figure

The diagram relates HECs to the spark pools from which they obtain parallel work. section 13.4.3

Putting work into the pool

`rpar x` creates a spark for `x` inside `Eval`; `runEval` retrieves the result. `return` does not wait for the spark to finish, so demand from the calling code can make the spark invalid before an HEC evaluates it—a fizzle. A spark for an already evaluated value is a dud. section 13.4.3

runEval $ do
  x' <- rpar x
  return x'

This small `Eval` computation sparks `x`, placing its possible parallel evaluation under runtime scheduling. section 13.4.3

Pool capacity matters. Making a spark for every small unit of work can overflow the pool, leaving parallelism ineffective. For a large collection, split work into larger chunks and spark those chunks instead; this reduces the number of sparks while preserving parallel work. section 13.4.3 section 13.5

Chunking an image mapping

A vector mapping strategy using `evalTraversable rpar` produced 1,318,768 sparks, including 1,210,301 overflows. A `parVectorChunk` strategy instead divides the vector into chunks and sequentially evaluates each chunk, producing 1,001 converted sparks with no overflows in the reported run. section 13.4.3

Listing 13.25 A module for chunked parallel execution of the Vector type
module Data.Vector.Strategies (parVectorChunk) where

import Control.Parallel.Strategies     #1
import qualified Data.Vector as V      #1

parVectorChunk :: Int -> Strategy (V.Vector a)
parVectorChunk size =
  fmap V.fromList . parListChunk size rseq . V.toList  #2

`parVectorChunk` converts a vector to chunks, evaluates each chunk with `rseq`, and rebuilds the vector. section 13.4.3

How Learn Haskell by Example covers it

How deep it goes
Explains spark creation, HEC work stealing, fizzles, duds, overflow, and chunking while deferring runtime cleanup details.
Examples
Uses `runEval` with `rpar`, list strategies, vector image mapping, spark statistics, and a chunked-vector strategy.
What it assumes
Introduces sparks through thunks and demonstrates Eval-based parallel evaluation without requiring prior parallel-runtime knowledge.
What you can do after
Apply it via Control.Parallel.Strategies by chunking collection work to avoid spark-pool overflow.
How it connects
Connects spark pools with sparks, thunks, Haskell execution contexts, work stealing, Eval, rpar, and evaluation strategies.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.