惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
L
LangChain Blog
博客园_首页
J
Java Code Geeks
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
WordPress大学
WordPress大学
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
U
Unit 42
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Announcements
Recent Announcements
C
Check Point Blog
IT之家
IT之家
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
D
Docker
有赞技术团队
有赞技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
阮一峰的网络日志
阮一峰的网络日志
I
InfoQ

ashishb.net

A day in Luxembourg - the richest country in the world I was asked to install malware during a fake interview Book summary: Breakneck - China's quest to engineer the future by Dan Wang Book summary: How to Teach Your Baby to Read Book Summary: The Discontented Little Baby Book by Pamela Douglas Introducing Amazing Sandbox - run third-party tools and AI agents securely on your machine Why software outsourcing gets a bad reputation? Book summary: The Natural Baby Sleep Solution by Polly Moore A day in Antwerp, Belgium Journey of online influencers Two days in Brussels, Belgium Shortcuts - when we love them and when we don't A visit to Rakhigarhi Three days in overhyped Paris Empty Japan, crowded Tokyo The real lock-in in GitHub is not the code, but the stars 11-day Norwegian Breakaway East Caribbean cruise Sanskrit and Sri Lankan Air Force Use REST with Open API The Achilles heel of American capitalism Costa Rica in 4 days At a juice stall in Sri Lanka A short stay at Warsaw, Poland Best practices for using Python & uv inside Docker Two days in Vilnius, Lithuania How IntelliJ IDEs waste disk space Pregnancy Why there aren't many digital nomads from India Two days in Riga, Latvia To keep your machine secure, run third-party tools inside Docker
It is hard to recommend Python in production
Ashish Bhatia · 2025-03-08 · via ashishb.net
TLDR NewsletterAwesome Python Weekly Newsletter

I started writing in the 2010s when Python 2 was going to be deprecated and Python 3 was too early to support. Python might have died there and then but was picked up by the data science and machine learning community, so, it survived. Running Python in production comes with various gotchas though.

Python is resource-intensive

Let’s consider a simple Docker image containing “Hello World”.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Build: docker buildx build -t python-fastapi -f Dockerfile_python .
# Size: docker image inspect python-fastapi --format='{{.Size}}' | numfmt --to=iec-i
# Run: docker run -it --rm --cpus=1 --memory=100m -p 8000:8000 python-fastapi
FROM python:3.12-slim AS base

WORKDIR /app
RUN pip3 install --no-cache-dir fastapi==0.115.11 uvicorn==0.34.0
SHELL ["/bin/bash", "-c"]
RUN echo -e "\
from fastapi import FastAPI\n\
app = FastAPI()\n\
@app.get('/')\n\
async def root():\n\
    return {'message': 'Hello World'}\
" > /app/web_server.py

ENTRYPOINT ["uvicorn", "web_server:app", "--host=0.0.0.0", "--port=8000", \
 "--workers=4", "--limit-concurrency=32"]

And a similar web server in Go.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Build: docker buildx build -t go-webserver -f Dockerfile.gobuild .
# Size: docker image inspect go-webserver --format='{{.Size}}' | numfmt --to=iec-i
# Run: docker run -it --rm --cpus=0.06 --memory=6m -p 8001:8001 go-webserver
FROM golang:1.24-alpine3.21 AS builder
WORKDIR /app
RUN apk add --no-cache bash ca-certificates tzdata
RUN go mod init ashishb.net/example
SHELL ["/bin/bash", "-c"]
RUN echo -e '\
package main\n\
\n\
import (\n\
    "fmt"\n\
    "net/http"\n\
)\n\
\n\
func helloHandler(w http.ResponseWriter, r *http.Request) {\n\
    fmt.Fprintf(w, "Hello, World!")\n\
}\n\
\n\
func main() {\n\
    http.HandleFunc("/", helloHandler)\n\
    http.ListenAndServe(":8001", nil)\n\
}' > /app/web_server.go
RUN go build -o ./webserver

FROM scratch AS runner
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /app/webserver /app/webserver

ENTRYPOINT ["/app/webserver"]

The Python docker image size is 164MiB while the Go docker image is 8MiB. Once you pull in any significant libraries, expect the Python image to balloon to 750MiB-1GiB range. The Go image, however, rarely crosses, 100MiB. Such large docker images are not great for auto-scaling during traffic spikes.

The other problem is that the Python image requires way more resources.

For example, the above Go-based web server when started with only 6MiB RAM (the lowest that Docker allows) performs as well as the Python build started under 16 times more RAM. Any RAM less than 100MiB and the Python-based server starts to hit OOM.

1
2
3
4
5
6
$ docker run -it --rm --cpus=0.06 --memory=6m -p 8001:8001 go-webserver
$ docker run -it --rm --cpus=1 --memory=100m -p 8000:8000 python-fastapi

# Similar performance when tested with
# h2load --h1 -n1000 -c40 'http://localhost:8000'
# h2load --h1 -n1000 -c40 'http://localhost:8001'

Further, the max concurrency of the FastAPI-based Python server is 40 while the one in Go is 150 (with only 6MiB of RAM). So, about a ~60X RAM difference. Coincidentally, a friend in YouTube infrastructure, who was involved in a fairly large migration from Python to C++, told me that cost reduction was about 60X.

This has huge implications for the financial costs and engineering hiring.

Imagine if your COGS are 20%.

So, you spend $20 for every $100 earned and half of it goes to hosting and serving costs. What if you can redirect 98% (~59/60) of that and spend that on hiring better engineers!

Python deployments have a larger attack surface

Consider the earlier mentioned docker images and let’s look at the vulnerabilities using Trivy.

1
2
3
$ trivy image go-webserver --quiet
...
0 vulnerabilities
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ trivy image python-fastapi --quiet
...
Total: 99 (UNKNOWN: 0, LOW: 71, MEDIUM: 26, HIGH: 1, CRITICAL: 1)
...

# Even Google's distroless image has vulnerabilities!
$ trivy image gcr.io/distroless/python3-debian12
...
Total: 52 (UNKNOWN: 0, LOW: 34, MEDIUM: 15, HIGH: 2, CRITICAL: 1)
...

While not all of these might be exploitable, but the attack surface is drastically larger.

Python codebase is hard to maintain

While it is easy to write baseline Python.
Far and few engineers can write good quality Python code.
Few understand the GIL limitations that Facebook is offering three engineers to fix.
Few know about common Python exceptions. A side note for those who know Java, all exceptions are unchecked in Python.
Few prevent new class fields assignments outside the constructor.
More often than not, you will see dictionaries being passed from function to function as a loose form of object representation.

Python language and packages are hard to upgrade

A minor change to setuptools and the whole Python ecosystem broke on a Sunday afternoon. Or a patch version upgrade from Python 3.12.3 -> 3.12.4 broke langchain. I have upgraded several production and hobby projects in Java, Go, and Python. Nothing is as painful as it is in the Python world.

The developer tooling for Go is written in Go.
The developer tooling for Rust is written in Rust.
The developer tooling for Java is written in Java.

However, look at the recent developments in Python tooling,

  • UV, the recommended Python package manager is written in Rust.
  • Ruff, the fastest Python linter is written in Rust.
  • Pydantic, the data class management system, migrated its core from Python in V1 to Rust in V2.

What if I have to use Python in production

See my follow-on post on this topic at How to use Python in production.

Post-publish Update

Seems like this post got famous.

Here are some interesting discussions from the web

  1. Linuxfr (French)
  2. TLDR Tech
  3. PyChina (Mandarin)
  4. Hacker news - where it is flagged by Python fanboys!
  5. Discu
  6. LibHunt newsletter