Speedups

April 10, 2026 · View on GitHub

CI Build Wheels PyPI Python License

C and Cython extensions for fast STL I/O and PostgreSQL-to-NumPy conversion.

Performance

Cython extensions run ~3x faster than pure Python, consistent across data sizes.

STL I/O Performance

OperationFacetsPure PythonspeedupsSpeedup
Write10,00028.5 ms9.9 ms2.9x
Read10,00021.6 ms7.0 ms3.1x
Write100,000283.4 ms89.3 ms3.2x
Read100,000218.7 ms71.0 ms3.1x
Write1,000,0002.81 s897.5 ms3.1x
Read1,000,0002.19 s711.5 ms3.1x
Write10,000,00028.62 s9.22 s3.1x
Read10,000,00022.03 s7.32 s3.0x

PostgreSQL COPY to NumPy Performance

TypeElementsPure PythonspeedupsSpeedup
int32100K7.3 ms2.6 ms2.8x
int321M73.8 ms24.8 ms3.0x
int3210M747.5 ms216.1 ms3.5x
int3250M3.75 s1.05 s3.6x
float64100K8.0 ms3.3 ms2.4x
float641M78.3 ms32.1 ms2.4x
float6410M786.5 ms268.5 ms2.9x
float6450M4.01 s1.31 s3.1x

Benchmarked on Apple M2 Pro, Python 3.14, macOS 15.4. PG data pre-populated in tables to isolate COPY+conversion time. Array dimensionality (1D/2D/3D) has no significant effect on performance.

Install

pip install speedups

With PostgreSQL support:

pip install speedups[postgres]

PostgreSQL Array → NumPy

Convert PostgreSQL arrays directly to NumPy ndarrays using psycopg's binary COPY protocol. Bypasses Python object creation for a significant speedup over the default loader.

Supports float4, float8, smallint, integer, and bigint arrays, from 1D to N-D.

import psycopg
from speedups.psycopg_loaders import NumpyLoader

with psycopg.connect("dbname=mydb") as conn:
    cursor = conn.cursor(binary=True)
    NumpyLoader.install(cursor)

    query = """
    COPY (
        SELECT array_agg(x)
        FROM generate_series(1, 100000) x
    ) TO STDOUT WITH BINARY
    """

    with cursor.copy(query) as copy:
        copy.set_types(["integer[]"])

        for row in copy.rows():
            print(row)  # numpy.ndarray

ASCII STL I/O

Read and write ASCII STL files at C speed. This module is used internally by numpy-stl — if you want to read or write STL files, use numpy-stl for a full-featured API. The Cython implementation uses direct sscanf/fprintf calls, avoiding Python string overhead entirely.

from speedups.stl import ascii_read, ascii_write

# Read
with open("model.stl", "rb") as f:
    buf = f.read(8192)
    name, mesh = ascii_read(f, buf)

# Write
with open("output.stl", "wb") as f:
    ascii_write(f, b"my_model", mesh)

Supported Types

PostgreSQLNumPyDimensions
float4float321D – ND
float8float641D – ND
smallintint161D – ND
integerint321D – ND
bigintint641D – ND

Compatibility

  • Python 3.10, 3.11, 3.12, 3.13, 3.14
  • NumPy 1.x and 2.x

License

BSD-3-Clause