2.1 Profiling applications with both IO and computing workloads2.1.1 Downloading data and computing minimum temperatures2.1.2 Python’s built-in profiling module2.1.3 Using local caches to reduce network usage2.2 Profiling code to detect performance bottlenecks2.2.1 Visualizing profiling information2.2.2 Line profiling2.2.3 The takeaway: Profiling code2.3 Optimizing basic data structures for speed: Lists, sets, and dictionaries2.3.1 Performance of list searches2.3.2 Searching using sets2.3.3 List, set, and dictionary complexity in Python2.4 Finding excessive memory allocation2.4.1 Navigating the minefield of Python memory estimation2.4.2 The memory footprint of some alternative representations2.4.3 Using arrays as a compact representation alternative to lists2.4.4 Systematizing what we have learned: Estimating memory usage of Python objects2.4.5 The takeaway: Estimating memory usage of Python objects2.5 Using laziness and generators for big-data pipelining2.5.1 Using generators instead of standard functionsSummary