What this book covers
Chapter 1, Benchmarking and Profiling, teaches you how to assess the performance of Python programs and practical strategies on how to identify and isolate slow sections of your code.
Chapter 2, Pure Python Optimizations, discusses how to improve your running times by orders of magnitude using the efficient data structures and algorithms available in the Python standard library and pure-Python third-party modules.
Chapter 3, Fast Array Operations with NumPy, Pandas, and Xarray, offers a guide to the NumPy and pandas packages. Mastery of these packages will allow you to implement fast numerical algorithms with an expressive, concise interface.
Chapter 4, C Performance with Cython, is a tutorial on Cython, a language that uses a Python-compatible syntax to generate efficient C code.
Chapter 5, Exploring Compilers, covers tools that can be used to compile Python to efficient machine code. The chapter will teach you how to use Numba, an optimizing compiler for Python functions, and PyPy, an alternative interpreter that can execute and optimize Python programs on the fly.
Chapter 6, Automatic Differentiation and Accelerated Linear Algebra for Machine Learning, covers high-performance Python programming, which is essential in scientific computing and machine learning. JAX implements many compiler-related optimizations under the hood, which speeds up NumPy operations by a significant amount. Further, the tool can automatically differentiate native Python functions, allowing for the wide application of gradient-based optimization routines.
Chapter 7, Implementing Concurrency, offers a guide to asynchronous and reactive programming. We will learn about key terms and concepts, and demonstrate how to write clean, concurrent code using the asyncio and RxPy frameworks.
Chapter 8, Parallel Processing, provides an introduction to parallel programming on multi-core processors and GPUs. In this chapter, you will learn how to achieve parallelism using the multiprocessing module and by expressing your code using Theano and TensorFlow.
Chapter 9, Concurrent Web Requests, covers one of the main applications of concurrent programming: web scraping. It also covers other relevant elements of web scraping, before discussing how threading can be applied to parallelize this process.
Chapter 10, Concurrent Image Processing, goes into a specific application of concurrency: image processing. The basic ideas behind image processing, in addition to some of the most common processing techniques, are discussed. We will, of course, see how concurrency, specifically multiprocessing, can speed up the task of image processing.
Chapter 11, Building Communication Channels with asyncio, combines the knowledge obtained regarding asynchronous programming covered in previous chapters with the topic of network communication. Specifically, we will look into using the aiohttp module as a tool to make asynchronous HTTP requests to web servers, as well as the aiofile module that implements asynchronous file reading/writing.
Chapter 12, Deadlocks, introduces the first of the problems that are commonly faced in concurrent programming. We will learn about the classical dining philosophers problem as an example of how deadlocks can cause concurrent programs to stop functioning. This chapter also covers a number of potential approaches to deadlocks as well as relevant concepts, such as livelocks and distributed deadlocks.
Chapter 13, Starvation, considers another common problem in concurrent applications. The chapter uses the narrative of the classical readers-writers problem to explain the concept of starvation and its causes. We will, of course, also discuss potential solutions to these problems via hands-on examples in Python.
Chapter 14, Race Conditions, addresses arguably the most well-known concurrency problem: race conditions. We will also discuss the concept of a critical section, which is an essential element in the context of race conditions specifically, and concurrent programming in general. The chapter then covers mutual exclusion as a potential solution for this problem.
Chapter 15, The Global Interpreter Lock, introduces the infamous GIL, which is considered the biggest challenge in concurrent programming in Python. We will learn about the reason behind the GIL's implementation and the problems that it raises. This chapter concludes with some thoughts regarding how Python programmers and developers should think about and interact with the GIL.
Chapter 16, The Factory Pattern, teaches you how to use the Factory design pattern (Factory Method and Abstract Factory) to initialize objects, and also covers the benefits of using the Factory design pattern instead of direct object instantiation.
Chapter 17, The Builder Pattern, teaches you how to simplify the object creation process for cases typically composed of several related objects. We will review real-world examples and use cases, and then implement the builder pattern in developing a pizza-ordering application.
Chapter 18, Other Creational Patterns, teaches you how to handle other object creation situations with techniques such as creating a new object that is a full copy (a named clone) of an existing object, a technique offered by the Prototype pattern. You will also learn about the Singleton pattern.
Chapter 19, The Adapter Pattern, teaches you how to make your existing code compatible with a foreign interface (for example, an external library) with minimal changes. Specifically, you will see how you can achieve interface conformance using the Adapter pattern without modifying the source code of the incompatible model.
Chapter 20, The Decorator Pattern, teaches you how to enhance the functionality of an object without using inheritance. We will mention several categories of cross-cutting concerns and specifically demonstrate memoization in this view. We will also describe how decorators can help us to keep our functions clean, without sacrificing performance.
Chapter 21, The Bridge Pattern, teaches you how to externalize an object's implementation details from its class hierarchy to another object class hierarchy. This chapter encourages the idea of preferring composition over inheritance.
Chapter 22, The Façade Pattern, teaches you how to create a single entry point to hide the complexity of a system. We will cover the basic use cases of facade and the implementation of the interface used by a multiserver operating system.
Chapter 23, Other Structural Patterns, teaches you about the Flyweight, Model-View-Controller (MVC), and Proxy patterns. With the Flyweight pattern, you will learn how to reuse objects from an object pool to improve the memory usage and possibly the performance of your applications. The MVC pattern is used in application development (desktop and the web) to improve maintainability by avoiding mixing the business logic with the user interface. And with the Proxy pattern, you provide a special object that acts as a surrogate or placeholder for another object to control access to it and reduce complexity and/or improve performance.
Chapter 24, The Chain of Responsibility Pattern, teaches you another technique to improve the maintainability of your applications by avoiding mixing the business logic with the user interface.
Chapter 25, The Command Pattern, teaches you how to encapsulate operations (such as undo, copy, and paste) as objects, to improve your application. Among the advantages of this technique, the object that invokes the command is decoupled from the object that performs it.
Chapter 26, The Observer Pattern, teaches you how to send a request to multiple receivers.