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

推荐订阅源

T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
L
LINUX DO - 热门话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
V
V2EX
GbyAI
GbyAI
量子位
Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
S
SegmentFault 最新的问题
O
OpenAI News
N
News and Events Feed by Topic
博客园 - Franky
爱范儿
爱范儿
Forbes - Security
Forbes - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V2EX - 技术
V2EX - 技术
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
P
Privacy International News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
Last Week in AI
Last Week in AI
罗磊的独立博客
Spread Privacy
Spread Privacy
Recent Announcements
Recent Announcements
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
AWS News Blog
AWS News Blog
The Register - Security
The Register - Security
Y
Y Combinator Blog
J
Java Code Geeks
I
Intezer

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 Family Ties in Your DNA: Some relatives are closer than others Doctors per capita Two days in Tallinn, Estonia Ship tools as standalone static binaries Made in America Two days in Helsinki, Finland Maintaining an Android app is a lot of work The land of good deals Two days in Oslo, Norway FastAPI vs Flask performance comparison Google Search is losing to Perplexity Two days in Dublin, Ireland Continuous integration ≠ Continuous delivery World's simplest project success heuristic London in 5 days Inflation, IRS, Credit cards, and Vendors Temu and the Chinese approach Things to do in Miami Florida Revenue vs Cost Axis Language learning as an adult The unanchored babies of the green card limbo Price variance in the United States A day in Louisville, Kentucky A surprisingly positive experience with Air India Unhospitable Airports Android: Don't use stale views USA = Union of Sales and Advertisement A day in Nashville, Tennessee Minimize Javascript in your codebase A day in Birmingham, Alabama In defense of ad-supported products Real vs artificial world The science behind Punjabi singers Hiking Mt. Fuji The Indian startup bubble is insane Repairing database on the fly for millions of users Book Summary: One up on Wall Street by Peter Lynch It is hard to recommend Google Cloud At the Prague airport Kyoto in three days Migrating from WordPress to Hugo Book summary: Sick Societies by Robert B. Edgerton Statistical outcomes require statistical games Illegal immigrants to Europe via Cairo Tokyo in three days Mobs are Status Games Writing Script matters as much as the spoken language Sri Lanka in 5 days LLMs: great for business but bad business Book Summary: Safe Haven by Mark Spitznagel Mac shortcut for typing Avagraha symbol On a bus with an asylum seeker Nicaragua in 5 days When to commit Generated code to version control Why I always buy a local SIM in a foreign country Use Makefile for Android Four days in Guadalajara, Mexico Android Navigation: Up vs Back Hotels vs Airbnb vs Hostels Currency issues in Argentina Abstractions should be deep not wide Some data on podcasting Always support compressed response in an API service A day in El Calafate - Patagonia, Argentina Hermetic docker images with Hugging Face machine learning models American Elections The sound of "ch" API services should always have usage Limits Hiking in El Chaltén - trekking capital of Argentina Natural Laws vs Man-made Laws
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