Concurrency in .NET

Book description

Concurrency in .NET teaches you how to build concurrent and scalable programs in .NET using the functional paradigm. This intermediate-level guide is aimed at developers, architects, and passionate computer programmers who are interested in writing code with improved speed and effectiveness by adopting a declarative and pain-free programming style.



About the Technology

Unlock the incredible performance built into your multi-processor machines. Concurrent applications run faster because they spread work across processor cores, performing several tasks at the same time. Modern tools and techniques on the .NET platform, including parallel LINQ, functional programming, asynchronous programming, and the Task Parallel Library, offer powerful alternatives to traditional thread-based concurrency.



About the Book

Concurrency in .NET teaches you to write code that delivers the speed you need for performance-sensitive applications. Featuring examples in both C# and F#, this book guides you through concurrent and parallel designs that emphasize functional programming in theory and practice. You’ll start with the foundations of concurrency and master essential techniques and design practices to optimize code running on modern multiprocessor systems.



What's Inside

  • The most important concurrency abstractions
  • Employing the agent programming model
  • Implementing real-time event-stream processing
  • Executing unbounded asynchronous operations
  • Best concurrent practices and patterns that apply to all platforms


About the Reader

For readers skilled with C# or F#.



About the Author

Riccardo Terrell is a seasoned software engineer and Microsoft MVP who is passionate about functional programming. He has over 20 years’ experience delivering cost-effective technology solutions in a competitive business environment.

Riccardo is well known and actively involved in the functional programming community, including .NET meetups and international conferences. He believes in multi-paradigm programming as a mechanism to maximize the power of code. You can keep up with Riccardo and his coding adventures on his blog www.rickyterrell.com.



Quotes
A complementary source of knowledge about modern concurrent functional programming on the .NET platform—an absolute must-read.
- Pawel Klimczyk

Not just for those cutting code on Windows. You can use the gold dust in this book on any platform!
- Kevin Orr

Presents real-world problems and offers different kinds of concurrency to solve them.
- Andy Kirsch

Easiest entry into concurrency I’ve come across so far!
- Anton Herzog

Publisher resources

View/Submit Errata

Table of contents

  1. Cover
  2. Titlepage
  3. Dedication
  4. preface
  5. Acknowledgments
  6. About This Book
    1. Who should read this book
    2. How this book is organized: a roadmap
    3. About the code
    4. Book forum
  7. About the Author
  8. About the Cover Illustration
  9. Part 1 : Benefits of functional programming applicable to concurrent programs
    1. Chapter 1: Functional concurrency foundations
      1. 1.1 What you’ll learn from this book
      2. 1.2 Let’s start with terminology
        1. 1.2.1 Sequential programming performs one task at a time
        2. 1.2.2 Concurrent programming runs multiple tasks at the same time
        3. 1.2.3 Parallel programming executes multiples tasks simultaneously
        4. 1.2.4 Multitasking performs multiple tasks concurrently over time
        5. 1.2.5 Multithreading for performance improvement
      3. 1.3 Why the need for concurrency?
        1. 1.3.1 Present and future of concurrent programming
      4. 1.4 The pitfalls of concurrent programming
        1. 1.4.1 Concurrency hazards
        2. 1.4.2 The sharing of state evolution
        3. 1.4.3 A simple real-world example: parallel quicksort
        4. 1.4.4 Benchmarking in F#
      5. 1.5 Why choose functional programming for concurrency?
        1. 1.5.1 Benefits of functional programming
      6. 1.6 Embracing the functional paradigm
      7. 1.7 Why use F# and C# for functional concurrent programming?
      8. Summary
    2. Chapter 2: Functional programming techniques for concurrency
      1. 2.1 Using function composition to solve complex problems
        1. 2.1.1 Function composition in C#
        2. 2.1.2 Function composition in F#
      2. 2.2 Closures to simplify functional thinking
        1. 2.2.1 Captured variables in closures with lambda expressions
        2. 2.2.2 Closures in a multithreading environment
      3. 2.3 Memoization-caching technique for program speedup
      4. 2.4 Memoize in action for a fast web crawler
      5. 2.5 Lazy memoization for better performance
        1. 2.5.1 Gotchas for function memoization
      6. 2.6 Effective concurrent speculation to amortize the cost of expensive computations
        1. 2.6.1 Precomputation with natural functional support
        2. 2.6.2 Let the best computation win
      7. 2.7 Being lazy is a good thing
        1. 2.7.1 Strict languages for understanding concurrent behaviors
        2. 2.7.2 Lazy caching technique and thread-safe Singleton pattern
        3. 2.7.3 Lazy support in F#
        4. 2.7.4 Lazy and Task, a powerful combination
      8. Summary
    3. Chapter 3: Functional data structures and immutability
      1. 3.1 Real-world example: hunting the thread-unsafe object
        1. 3.1.1 .NET immutable collections: a safe solution
        2. 3.1.2 .NET concurrent collections: a faster solution
        3. 3.1.3 The agent message-passing pattern: a faster, better solution
      2. 3.2 Safely sharing functional data structures among threads
      3. 3.3 Immutability for a change
        1. 3.3.1 Functional data structure for data parallelism
        2. 3.3.2 Performance implications of using immutability
        3. 3.3.3 Immutability in C#
        4. 3.3.4 Immutability in F#
        5. 3.3.5 Functional lists: linking cells in a chain
        6. 3.3.6 Building a persistent data structure: an immutable binary tree
      4. 3.4 Recursive functions: a natural way to iterate
        1. 3.4.1 The tail of a correct recursive function: tail-call optimization
        2. 3.4.2 Continuation passing style to optimize recursive function
      5. Summary
  10. Part 2: How to approach the different parts of a concurrent program
    1. Chapter 4: The basics of processing big data: data parallelism, part 1
      1. 4.1 What is data parallelism?
        1. 4.1.1 Data and task parallelism
        2. 4.1.2 The “embarrassingly parallel” concept
        3. 4.1.3 Data parallelism support in .NET
      2. 4.2 The Fork/Join pattern: parallel Mandelbrot
        1. 4.2.1 When the GC is the bottleneck: structs vs. class objects
        2. 4.2.2 The downside of parallel loops
      3. 4.3 Measuring performance speed
        1. 4.3.1 Amdahl’s Law defines the limit of performance improvement
        2. 4.3.2 Gustafson’s Law: a step further to measure performance improvement
        3. 4.3.3 The limitations of parallel loops: the sum of prime numbers
        4. 4.3.4 What can possibly go wrong with a simple loop?
        5. 4.3.5 The declarative parallel programming model
      4. Summary
    2. Chapter 5: PLINQ and MapReduce: data parallelism, part 2
      1. 5.1 A short introduction to PLINQ
        1. 5.1.1 How is PLINQ more functional?
        2. 5.1.2 PLINQ and pure functions: the parallel word counter
        3. 5.1.3 Avoiding side effects with pure functions
        4. 5.1.4 Isolate and control side effects: refactoring the parallel word counter
      2. 5.2 Aggregating and reducing data in parallel
        1. 5.2.1 Deforesting: one of many advantages to folding
        2. 5.2.2 Fold in PLINQ: Aggregate functions
        3. 5.2.3 Implementing a parallel Reduce function for PLINQ
        4. 5.2.4 Parallel list comprehension in F#: PSeq
        5. 5.2.5 Parallel arrays in F#
      3. 5.3 Parallel MapReduce pattern
        1. 5.3.1 The Map and Reduce functions
        2. 5.3.2 Using MapReduce with the NuGet package gallery
      4. Summary
    3. Chapter 6: Real-time event streams: functional reactive programming
      1. 6.1 Reactive programming: big event processing
      2. 6.2. NET tools for reactive programming
        1. 6.2.1 Event combinators—a better solution
        2. 6.2.2 .NET interoperability with F# combinators
      3. 6.3 Reactive programming in .NET: Reactive Extensions (Rx)
        1. 6.3.1 From LINQ/PLINQ to Rx
        2. 6.3.2 IObservable: the dual IEnumerable
        3. 6.3.3 Reactive Extensions in action
        4. 6.3.4 Real-time streaming with RX
        5. 6.3.5 From events to F# observables
      4. 6.4 Taming the event stream: Twitter emotion analysis using Rx programming
        1. 6.4.1 SelectMany: the monadic bind operator
      5. 6.5 An Rx publisher-subscriber
        1. 6.5.1 Using the Subject type for a powerful publisher-subscriber hub
        2. 6.5.2 Rx in relation to concurrency
        3. 6.5.3 Implementing a reusable Rx publisher-subscriber
        4. 6.5.4 Analyzing tweet emotions using an Rx Pub-Sub class
        5. 6.5.5 Observers in action
        6. 6.5.6 The convenient F# object expression
      6. Summary
    4. Chapter 7: Task-based functional parallelism
      1. 7.1 A short introduction to task parallelism
        1. 7.1.1 Why task parallelism and functional programming?
        2. 7.1.2 Task parallelism support in .NET
      2. 7.2 The .NET Task Parallel Library
        1. 7.2.1 Running operations in parallel with TPL Parallel.Invoke
      3. 7.3 The problem of void in C#
        1. 7.3.1 The solution for void in C#: the unit type
      4. 7.4 Continuation-passing style: a functional control flow
        1. 7.4.1 Why exploit CPS?
        2. 7.4.2 Waiting for a task to complete: the continuation model
      5. 7.5 Strategies for composing task operations
        1. 7.5.1 Using mathematical patterns for better composition
        2. 7.5.2 Guidelines for using tasks
      6. 7.6 The parallel functional Pipeline pattern
      7. Summary
    5. Chapter 8: Task asynchronicity for the win
      1. 8.1 The Asynchronous Programming Model (APM)
        1. 8.1.1 The value of asynchronous programming
        2. 8.1.2 Scalability and asynchronous programming
        3. 8.1.3 CPU-bound and I/O-bound operations
      2. 8.2 Unbounded parallelism with asynchronous programming
      3. 8.3 Asynchronous support in .NET
        1. 8.3.1 Asynchronous programming breaks the code structure
        2. 8.3.2 Event-based Asynchronous Programming
      4. 8.4 C# Task-based Asynchronous Programming
        1. 8.4.1 Anonymous asynchronous lambdas
        2. 8.4.2 Task<T> is a monadic container
      5. 8.5 Task-based Asynchronous Programming: a case study
        1. 8.5.1 Asynchronous cancellation
        2. 8.5.2 Task-based asynchronous composition with the monadic Bind operator
        3. 8.5.3 Deferring asynchronous computation enables composition
        4. 8.5.4 Retry if something goes wrong
        5. 8.5.5 Handling errors in asynchronous operations
        6. 8.5.6 Asynchronous parallel processing of the historical stock market
        7. 8.5.7 Asynchronous stock market parallel processing as tasks complete
      6. Summary
    6. Chapter 9: Asynchronous functional programming in F#
      1. 9.1 Asynchronous functional aspects
      2. 9.2 What’s the F# asynchronous workflow?
        1. 9.2.1 The continuation passing style in computation expressions
        2. 9.2.2 The asynchronous workflow in action: Azure Blob storage parallel operations
      3. 9.3 Asynchronous computation expressions
        1. 9.3.1 Difference between computation expressions and monads
        2. 9.3.2 AsyncRetry: building your own computation expression
        3. 9.3.3 Extending the asynchronous workflow
        4. 9.3.4 Mapping asynchronous operation: the Async.map functor
        5. 9.3.5 Parallelize asynchronous workflows: Async.Parallel
        6. 9.3.6 Asynchronous workflow cancellation support
        7. 9.3.7 Taming parallel asynchronous operations
      4. Summary
    7. Chapter 10: Functional combinators for fluent concurrent programming
      1. 10.1 The execution flow isn’t always on the happy path: error handling
        1. 10.1.1 The problem of error handling in imperative programming
        2. 10.2.1 Error handling in FP: exceptions for flow control
        3. 10.2.2 Handling errors with Task<Option<T>> in C#
        4. 10.2.3 The F# AsyncOption type: combining Async and Option
        5. 10.2.4 Idiomatic F# functional asynchronous error handling
        6. 10.2.5 Preserving the exception semantic with the Result type
      2. 10.3 Taming exceptions in asynchronous operations
        1. 10.3.1 Modeling error handling in F# with Async and Result
        2. 10.3.2 Extending the F# AsyncResult type with monadic bind operators
      3. 10.4 Abstracting operations with functional combinators
      4. 10.5 Functional combinators in a nutshell
        1. 10.5.1 The TPL built-in asynchronous combinators
        2. 10.5.2 Exploiting the Task.WhenAny combinator for redundancy and interleaving
        3. 10.5.3 Exploiting the Task.WhenAll combinator for asynchronous for-each
        4. 10.5.4 Mathematical pattern review: what you’ve seen so far
      5. 10.6 The ultimate parallel composition applicative functor
        1. 10.6.1 Extending the F# async workflow with applicative functor operators
        2. 10.6.2 Applicative functor semantics in F# with infix operators
        3. 10.6.3 Exploiting heterogeneous parallel computation with applicative functors
        4. 10.6.4 Composing and executing heterogeneous parallel computations
        5. 10.6.5 Controlling flow with conditional asynchronous combinators
        6. 10.6.6 Asynchronous combinators in action
      6. Summary
    8. Chapter 11: Applying reactive programming everywhere with agents
      1. 11.1 What’s reactive programming, and how is it useful?
      2. 11.2 The asynchronous message-passing programming model
        1. 11.2.1 Relation with message passing and immutability
        2. 11.2.2 Natural isolation
      3. 11.3 What is an agent?
        1. 11.3.1 The components of an agent
        2. 11.3.2 What an agent can do
        3. 11.3.3 The share-nothing approach for lock-free concurrent programming
        4. 11.3.4 How is agent-based programming functional?
        5. 11.3.5 Agent is object-oriented
      4. 11.4 The F# agent: MailboxProcessor
        1. 11.4.1 The mailbox asynchronous recursive loop
      5. 11.5 Avoiding database bottlenecks with F# MailboxProcessor
        1. 11.5.1 The MailboxProcessor message type: discriminated unions
        2. 11.5.2 MailboxProcessor two-way communication
        3. 11.5.3 Consuming the AgentSQL from C#
        4. 11.5.4 Parallelizing the workflow with group coordination of agents
        5. 11.5.5 How to handle errors with F# MailboxProcessor
        6. 11.5.6 Stopping MailboxProcessor agents—CancellationToken
        7. 11.5.7 Distributing the work with MailboxProcessor
        8. 11.5.8 Caching operations with an agent
        9. 11.5.9 Reporting results from a MailboxProcessor
        10. 11.5.10 Using the thread pool to report events from MailboxProcessor
      6. 11.6 F# MailboxProcessor: 10,000 agents for a game of life
      7. Summary
    9. Chapter 12: Parallel workflow and agent programming with TPL Dataflow
      1. 12.1 The power of TPL Dataflow
      2. 12.2 Designed to compose: TPL Dataflow blocks
        1. 12.2.1 Using BufferBlock<TInput> as a FIFO buffer
        2. 12.2.2 Transforming data with TransformBlock<TInput, TOutput>
        3. 12.2.3 Completing the work with ActionBlock<TInput >
        4. 12.2.4 Linking dataflow blocks
      3. 12.3 Implementing a sophisticated Producer/Consumer with TDF
        1. 12.3.1 A multiple Producer/single Consumer pattern: TPL Dataflow
        2. 12.3.2 A single Producer/multiple Consumer pattern
      4. 12.4 Enabling an agent model in C# using TPL Dataflow
        1. 12.4.1 Agent fold-over state and messages: Aggregate
        2. 12.4.2 Agent interaction: a parallel word counter
      5. 12.5 A parallel workflow to compress and encrypt a large stream
        1. 12.5.1 Context: the problem of processing a large stream of data
        2. 12.5.2 Ensuring the order integrity of a stream of messages
        3. 12.5.3 Linking, propagating, and completing
        4. 12.5.4 Rules for building a TDF workflow
        5. 12.5.5 Meshing Reactive Extensions (Rx) and TDF
      6. Summary
  11. Part 3: Modern patterns of concurrent programming applied
    1. Chapter 13: Recipes and design patterns for successful concurrent programming
      1. 13.1 Recycling objects to reduce memory consumption
        1. 13.1.1 Solution: asynchronously recycling a pool of objects
      2. 13.2 Custom parallel Fork/Join operator
        1. 13.2.1 Solution: composing a pipeline of steps forming the Fork/Join pattern
      3. 13.3 Parallelizing tasks with dependencies: designing code to optimize performance
        1. 13.3.1 Solution: implementing a dependencies graph of tasks
      4. 13.4 Gate for coordinating concurrent I/O operations sharing resources: one write, multiple reads
        1. 13.4.1 Solution: applying multiple read/write operations to shared thread-safe resources
      5. 13.5 Thread-safe random number generator
        1. 13.5.1 Solution: using the ThreadLocal object
      6. 13.6 Polymorphic event aggregator
        1. 13.6.1 Solution: implementing a polymorphic publisher-subscriber pattern
      7. 13.7 Custom Rx scheduler to control the degree of parallelism
        1. 13.7.1 Solution: implementing a scheduler with multiple concurrent agents
      8. 13.8 Concurrent reactive scalable client/server
        1. 13.8.1 Solution: combining Rx and asynchronous programming
      9. 13.9 Reusable custom high-performing parallel filter‑map operator
        1. 13.9.1 Solution: combining filter and map parallel operations
      10. 13.10 Non-blocking synchronous message-passing model
        1. 13.10.1 Solution: coordinating the payload between operations using the agent programming model
      11. 13.11 Coordinating concurrent jobs using the agent programming model
        1. 13.11.1 Solution: implementing an agent that runs jobs with a configured degree of parallelism
      12. 13.12 Composing monadic functions
        1. 13.12.1 Solution: combining asynchronous operations using the Kleisli composition operator
      13. Summary
    2. Chapter 14: Building a scalable mobile app with concurrent functional programming
      1. 14.1 Functional programming on the server in the real world
      2. 14.2 How to design a successful performant application
        1. 14.2.1 The secret sauce: ACD
        2. 14.2.2 A different asynchronous pattern: queuing work for later execution
      3. 14.3 Choosing the right concurrent programming model
        1. 14.3.1 Real-time communication with SignalR
      4. 14.4 Real-time trading: stock market high-level architecture
      5. 14.5 Essential elements for the stock market application
      6. 14.6 Let’s code the stock market trading application
        1. 14.6.1 Benchmark to measure the scalability of the stock ticker application
      7. Summary
  12. Appendix A: Functional programming
    1. What is functional programming?
      1. The benefits of functional programming
      2. The tenets of functional programming
    2. The clash of program paradigms: from imperative to object-oriented to functional programming
      1. Higher-order functions for increasing abstraction
      2. HOFs and lambda expressions for code reusability
      3. Lambda expressions and anonymous functions
      4. Currying
      5. Partially applied functions
      6. Power of partial function application and currying in C#
  13. Appendix B: F# overview
    1. The let binding
    2. Understanding function signatures in F#
    3. Creating mutable types: mutable and ref
    4. Functions as first-class types
    5. Composition: pipe and composition operators
    6. Delegates
    7. Comments
    8. Open statements
    9. Basic data types
    10. Special string definition
    11. Tuple
    12. Record types
    13. Discriminated unions
    14. Pattern matching
    15. Active patterns
    16. Collections
    17. Arrays
    18. Sequences (seq)
    19. Lists
    20. Sets
    21. Maps
    22. Loops
    23. Classes and inheritance
    24. Abstract classes and inheritance
    25. Interfaces
    26. Object expressions
    27. Casting
    28. Units of measure
    29. Event module API reference
  14. Appendix C: Interoperability between an F# asynchronous workflow and .NET Task
  15. Index

Product information

  • Title: Concurrency in .NET
  • Author(s): Riccardo Terrell
  • Release date: July 2018
  • Publisher(s): Manning Publications
  • ISBN: 9781617292996