A CPU runs general-purpose computations with a relatively small number of fast computation units. Increasing CPU processing power now depends more on parallel units than on raw speed, making the way work is divided important to data-processing performance. section 1.2.1 section 9.4
Start with the workload, then profile it. Computing distances between every pair of NOAA stations is a CPU-intensive, quadratic task that also uses substantial memory. Python’s profiling tools help locate where its execution time goes before an optimization is chosen. section 2.2
A simplified execution comparison
To double 100 array elements, a single-core CPU model reads, doubles, and writes each value in sequence. With reads and writes priced at 90 time units each and doubling at 2, the total is 18,200 units. An idealized GPU model assigns one element to each of 100 concurrent threads and totals 240 units, despite slower computation per unit. These illustrative costs explain the advantage of parallel work; they are not benchmark results. section 9.1.1
Table 1.1 Memory hierarchy with sizes and access times for a hypothetical, but realistic modern desktop (view table figure)
Compare cache, RAM, and storage access times to see why the location of data can matter alongside CPU computation. section 1.2.1
A GPU is not a faster CPU for every job: its many simpler units favor large numbers of similar, independent operations and use a different memory and execution model. Moving standard Python code to a GPU therefore calls for a suitable library or a redesign around parallel work, rather than a direct transfer of sequential code. section 1.2.1 section 9.4



