Profiling Python with py-spy: 169 seconds down to 0.56

The usual advice for handling large datasets in Python is to write the logic and let it run. That holds up until the script becomes the reason a page hangs. It does not matter much whether you are building a custom WooCommerce integration or a standalone scraper: code that is slow enough is broken. Most developers still go digging through logs when a sampling profiler like py-spy would point straight at the bottleneck.

In 14 years of working on complex systems I have watched plenty of projects sink on silent bottlenecks, meaning code that returns the right answer but takes three minutes to do half a second of work. If you read what I wrote about WordPress core performance, you already know how I feel about scripts that sit on server resources for no reason.

Naive loops and where the overhead comes from

The trap I run into most often is Pandas iterrows(). It reads well, and it is slow, because it builds a fresh Series object for every single row. Take a real case: calculating the Haversine distance across 3.5 million flight records. The naive version looks like this.

# The Slow Approach: Using iterrows()
haversine_dists = []
for i, row in flights_df.iterrows():
    haversine_dists.append(haversine(
        lat_1=row["LATITUDE_ORIGIN"],
        lon_1=row["LONGITUDE_ORIGIN"],
        lat_2=row["LATITUDE_DEST"],
        lon_2=row["LONGITUDE_DEST"]
    ))
flights_df["Distance"] = haversine_dists

On a dataset that size the script needs close to 170 seconds, so nearly three minutes of the process doing nothing useful. In production that is long enough to hit a timeout and take the worker down with it.

Why py-spy for Python profiling

Tracers like cProfile add enough overhead of their own to skew the numbers they report. py-spy works differently. It is a sampling profiler: it sits outside your process and reads the call stack 100 times a second. Your program runs at normal speed and you still get an honest picture of where the CPU time goes.

Install it with pip and run the recorder:

pip install py-spy
py-spy record -o profile.svg -r 100 -- python main.py

Open the resulting SVG in a browser and you get an icicle graph. If the bar for iterrows() covers 70% of the width, that is the thing to refactor.

Vectorize instead of iterating

Once the profile tells you where the time goes, the fix is usually to get out of Python-level loops and into C-level vectorized operations with NumPy. That means rewriting the function so it takes arrays instead of one pair of coordinates at a time.

# The Optimized Approach: Vectorized NumPy
import numpy as np

def haversine_vectorized(lat_1, lon_1, lat_2, lon_2):
    lat_1_rad, lon_1_rad = np.radians(lat_1), np.radians(lon_1)
    lat_2_rad, lon_2_rad = np.radians(lat_2), np.radians(lon_2)
    
    # Logic remains the same, but operates on arrays
    delta_lat = lat_2_rad - lat_1_rad
    # ... calculation ...
    return result

flights_df["Distance"] = haversine_vectorized(
    flights_df["LATITUDE_ORIGIN"], 
    flights_df["LONGITUDE_ORIGIN"], 
    flights_df["LATITUDE_DEST"], 
    flights_df["LONGITUDE_DEST"]
)

Execution time drops from 169 seconds to 0.56 seconds, about 300 times faster. The Py-Spy documentation on GitHub covers the internals if you want them.

If performance work like this is eating your dev hours, I take it on. I have been wrestling with WordPress and high-load backend scripts since the 4.x days.

Measure before you refactor

Guessing where the lag lives costs more time than profiling does. Run py-spy, find the widest bar in the graph, rewrite that part, then measure again. The routine is the same whether the slow thing is a WordPress build or a large data migration.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.