Skip to content

Benchmarks ​

In one sentence

The headline numbers come from a Postgres run, committed in orders-api-demo/benchmarks/. The SQLite numbers are a laptop run for convenience, and the two differ on purpose.

Consolidated table ​

Each row names its environment. Postgres capture is the committed output from the Docker setup. SQLite local is the laptop default, and where a number is guidance rather than a committed file, it is marked expected.

PatternMetricBadGoodRatioEnvironmentSource
AP1Wall clock, 3 concurrent requests3.046 s1.040 sabout 2.9×Postgres captureap1-blocking/latency-3-concurrent.txt
AP1Wall clock, bridge (run_in_executor)n/a1.039 sn/aPostgres captureap1-blocking/latency-3-concurrent.txt
AP1Wall clock, 3 concurrent requestsabout 3.0 sabout 1.0 sabout 3×SQLite, expectedDEMO_GUIDE
AP2Mean latency, 50 sequential requests17.48 ms1.73 msabout 10×Postgres captureap2-di/latency-report.txt
AP2Mean latencyabout 5 to 6 msabout 1.3 msabout 4×SQLite, expectedDEMO_GUIDE
AP3Queries for 5 orders, echo=True623×Postgres captureap3-lazy-loading/echo-bad.log, echo-good.log
AP3Crash on plain attribute accessMissingGreenlet, HTTP 500n/an/aPostgres captureap3-lazy-loading/missing-greenlet-response.json
AP4cProfile total time, 200 orders × 200.056 s0.030 sabout 1.9×Postgres captureap4-pydantic/cprofile-bad.txt, cprofile-good.txt
AP4Function calls, same run204,481116,463about 1.8×Postgres capturesame
AP4Function callsabout 290kabout 111kabout 2.6×SQLite localworking-tree capture, see note
AP5Failure rate, locust 100 users, 20 s2.1% (19 of 905)0% (0 of 3370)n/aPostgres captureap5-pool/locust-bad_stats.csv, locust-good_stats.csv
AP5Throughput47.8 req/s179.3 req/s3.75×Postgres capturesame
AP5Median latency2200 ms530 msabout 4.2×Postgres capturesame
AP5Failure rate and throughputabout 40 to 45%, about 43 req/s0%, about 97 req/sn/aSQLite, expectedDEMO_GUIDE

Ratios are computed from the values shown: AP2 is 17.48 ÷ 1.73, AP5 throughput is 179.3 ÷ 47.8, and so on.

Methodology ​

PatternHow the number was produced
AP1Three concurrent curl requests to each endpoint, timed with time, against the dockerized app and the go-httpbin gateway. The gateway's /delay/1 takes one second.
AP1 (asyncio)PYTHONASYNCIODEBUG=1 with scripts/asyncio_debug_demo.py. The log records the slow callback warning.
AP2scripts/bench_ap2_di.py: 50 sequential requests to each endpoint, reporting mean, p50 and p95
AP3scripts/sqlalchemy_echo_demo.py with echo=True, counting statements for 5 orders. The test suite checks the same counts with a before_cursor_execute listener.
AP4scripts/pydantic_cprofile_demo.py: cProfile over 200 orders, repeated 20 times. Call counts are the stable comparison.
AP5locust --headless -u 100 -r 100 -t 20s against each pool profile, with a full app restart between profiles.

Call counts are more useful than wall time for AP4. They are stable across machines, while timings move with the hardware and load.

Postgres versus SQLite ​

The talk's numbers come from Postgres, and the difference is real.

EffectPostgresSQLite
Engine construction (AP2)A new TCP connection and authentication handshake each timeA local file, with no network handshake
Gap in AP2About 10×About 4×
Pool exhaustion (AP5)A real connection limit with real handshake costSame pool logic, but the demo holds connections longer so the starvation is reliable
Query count (AP3)IdenticalIdentical

The SQLite run understates AP2 and changes the AP5 shape on purpose. The demo's AP5 route holds a connection for 0.3 s on Postgres and 0.6 s on SQLite, as the code comment explains. Always label which environment a number came from when you present it.

Note on working-tree benchmark files ​

Some files under orders-api-demo/benchmarks/ were overwritten by a later local run and show as modified in git. The committed versions are the Postgres captures this page quotes. The uncommitted versions are not used for any Postgres number here.

The AP4 SQLite call counts (about 290k and 111k) come from the uncommitted working-tree cProfile files, which match the DEMO_GUIDE guidance. The AP5 working-tree CSVs show different totals from the committed capture, so they are not quoted.

Raw files ​

  • Committed capture folder: orders-api-demo/benchmarks/
  • Per-pattern READMEs: orders-api-demo/benchmarks/apN-*/README.md
  • The tests that assert the ratios: orders-api-demo/tests/test_ap*_*.py

Released under the MIT License. Speaker: Satyam Soni, PyCon Hong Kong 2026.