liveBook · Manning

Logical thread

As explained in Functional Programming in Scala, Second Edition

A logical thread is an independent line of computation used to describe concurrent execution without necessarily denoting a physical operating-system thread.

A logical thread is an independent line of computation that can be created freely for a problem and later mapped onto scarce operating-system threads. It describes concurrency without committing the program to a physical thread. section 7.1.1

Direct Thread and Runnable APIs make results depend on side effects and expose physical-thread management. Future and ExecutorService abstract over those threads, but blocking get still offers too little compositional structure. A functional parallelism API instead represents computation as a value such as Par[A], allowing parallel work to be combined before execution. section 7.1.1

Logical threads matter when:

  • Each element of a collection should receive its own concurrent computation rather than sharing one filtering thread. section 7.9
  • Nested fork operations create more logical work than the executor has physical threads, potentially leaving every worker blocked while another logical thread waits to run. section 7.9

Parallel filtering

A sequential implementation lifts as.filter(f) with unit or lazyUnit, but the predicate calls still share one logical thread. Mapping asyncF over the input gives each predicate invocation its own Par computation; sequence then combines the results and flatten removes rejected elements. section 7.9

def parFilter[A](as: List[A])(f: A => Boolean): Par[List[A]] =
  fork:                                    #1
    val pars: List[Par[List[A]]] =
      as.map(asyncF(a =>
        if f(a) then List(a) else Nil))    #2
    sequence(pars).map(_.flatten)          #3

The implementation makes logical-thread granularity visible: fork starts the overall computation, asyncF creates one computation per element, and sequence composes them. section 7.9

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines the physical-versus-logical distinction and traces parallel filtering and fixed-pool deadlock, without detailing scheduler internals.
Examples
Uses parallel filtering, asyncF, sequence, fork nesting, and fixed-size thread pools as concrete illustrations.
What it assumes
Assumes basic concurrency primitives and functional composition while contrasting Runnable, Thread, Future, and ExecutorService directly.
What you can do after
Apply it via Par by separating logical computation structure from executor-backed execution and recognizing a nested-fork deadlock risk.
How it connects
Connects logical threads to concurrency, operating-system threads, Par, Future, ExecutorService, compositionality, and deadlock.

Also explained in

Compare how 3 books explain logical thread →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.