我拿Hello World测了5种Web框架,结果出乎意料


一、选框架纠结症,让我决定自己测一把

去年团队要起一个新项目,技术选型会上吵了两个小时。有人说用Django,功能齐全;有人说用FastAPI,性能好;还有人说用Spring Boot,虽然重但稳。我听了半天,觉得每个人都在凭感觉和道听途说说话,没一个人真正在同一台机器上跑过对比。

于是会后我干了一件事:把大家提到的几种主流Web框架全装了一遍,每个框架写一个最简单的HTTP接口,返回”Hello World”。然后记录启动时间、内存占用和并发响应。整个过程花了我一个下午加晚上,测完心里就有数了。

我选的五个框架:Python的Flask和FastAPI、Node.js的Express、Java的Spring Boot,以及Go的Gin(虽然Go不是框架但Gin是主流)。都是最新稳定版。机器是我的MacBook Pro M1,16GB内存,系统干净,除了开发工具没跑别的服务。


二、测试方法:尽量公平,但难免有误差

每个框架我都写一个单独的项目,只依赖框架本身,不引入数据库、缓存或其他中间件。接口就一行:return "Hello, World!"或对应的写法。

启动时间:从执行启动命令(比如python app.py./gradlew bootRun)到终端显示”Listening on port 8000″这类信息为止,我拿手机秒表掐的,每个框架跑了三次取中位数。

内存占用:启动稳定后,用ps aux | grep看RSS(驻留内存)值,取稳定后的读数。

并发测试:我用wrk(一个压测工具)跑30秒并发100连接,看平均延迟和每秒请求数(RPS)。虽然Hello World极简,但能反映框架的基础处理能力。


三、逐一实测,每个都有让我意外的地方

先说Flask。这是Python里最轻量的框架之一。我写了三行代码:

python

复制

下载

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello(): return "Hello, World!"

启动命令flask run,终端显示启动完成大约花了0.8秒,非常快。内存占用22MB,算很低了。wrk压测结果:平均延迟6.2ms,RPS约16000。整个体验很顺畅,没什么毛病。不过Flask默认是同步的,如果你有I/O阻塞操作,性能会明显下降,但Hello World测不出来。对于简单API,Flask的轻量和快速启动是个优势。

然后是FastAPI。最近很火,异步加持。代码稍微多点:

python

复制

下载

from fastapi import FastAPI
app = FastAPI()
@app.get('/')
def hello(): return {"message": "Hello, World!"}

启动命令uvicorn main:app,启动时间0.9秒,跟Flask差不多。内存29MB,略高于Flask。wrk压测让我有点意外:平均延迟3.1ms,RPS直接飙到21000。明显比Flask快,异步框架在处理简单请求时确实有优势。但FastAPI默认返回JSON而不是纯文本,我试了改成Response("Hello World")纯文本,延迟降到2.8ms,差别不大。FastAPI启动略慢一丁点,但性能更好,而且自带自动文档,如果项目需要API交互,它比Flask顺手。

再到Express(Node.js)。Node生态里最老牌的框架。代码如下:

javascript

复制

下载

const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello, World!'));
app.listen(3000);

启动命令node app.js,启动时间0.4秒,是五个里最快的。内存占用38MB,比Flask和FastAPI都高。wrk压测结果:平均延迟4.8ms,RPS约18000。介于Flask和FastAPI之间。Node的单线程事件循环在处理简单请求时表现不错,但CPU密集型就不行了。Hello World测试中,它的启动速度最快,适合快速原型或需要频繁重启的开发场景。

接下来是Go的Gin。编译型语言的优势在启动时就体现了。我写了:

go

复制

下载

package main
import "github.com/gin-gonic/gin"
func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(200, "Hello, World!")
    })
    r.Run()
}

我先编译成二进制go build,编译花了1.1秒(比我想象中快),然后执行二进制文件。启动时间0.01秒——真的太快了,秒表按下去还没反应过来就启动了。内存占用1.8MB,低得离谱。wrk压测结果:平均延迟1.2ms,RPS达到48000,把其他几个按在地上摩擦。Gin在性能上完胜,启动时间和资源消耗都是碾压级别。唯一要习惯的是编译步骤,但可以集成到CI里,部署时直接扔二进制就行。

最后是Spring Boot。Java的“重量级选手”。我用了Spring Initializr生成了一个只依赖Spring Web的项目。代码很简单:

java

复制

下载

@RestController
public class HelloController {
    @GetMapping("/")
    public String hello() { return "Hello, World!"; }
}

启动命令./gradlew bootRun,第一次启动花了7.2秒,包括Gradle初始化,但后续重启因为缓存,大概3.5秒左右。我取的平均是5次后的稳定值,约3.8秒。内存占用直接飙到220MB,比前面四个加起来还多。wrk压测结果倒不差:平均延迟2.3ms,RPS约35000,比Gin慢但比FastAPI快。启动慢、内存大,但运行时性能不弱。Spring Boot适合大型企业级应用,Hello World级的测试完全发挥不出它的优势,但它依然能跑出不错的吞吐量。


四、我把数据整理成了一张表

框架语言启动时间(s)内存(MB)平均延迟(ms)RPS
FlaskPython0.8226.216000
FastAPIPython0.9293.121000
ExpressNode0.4384.818000
GinGo0.011.81.248000
Spring BootJava3.82202.335000

看完这表,我第一个反应是:Gin太能打了,几乎全方位胜出。但冷静下来后,我觉得不能只看数据。


五、数据之外的感受

首先,启动时间对Serverless或短生命周期容器很重要。如果每次请求都冷启动,Gin和Express会占优,Spring Boot直接抬走。但如果你的服务是长驻的,启动时间的影响就很小。

其次,内存占用决定了你能在一台机器上跑多少个实例。Spring Boot一个实例220MB,在1GB内存的容器里只能跑3-4个;Gin能跑几百个。如果你的成本敏感,这点很关键。

然后,开发体验是无法量化的。Flask和FastAPI的代码写起来最舒服,Python的动态特性让你改完代码刷新就能看到变化;Spring Boot的依赖注入和AOP虽然重,但大型项目里很管用;Express中间件生态丰富,前端转后端的人上手快;Gin简洁但得习惯Go的静态类型和错误处理。

另外,框架的学习曲线也要考虑。Flask和Express几乎零门槛,FastAPI稍复杂一点因为有异步和类型注解,Spring Boot的注解体系需要时间熟悉,Gin对没写过Go的人有点别扭。


六、我的最终建议

如果你只是写个小工具、内部API或者轻量服务,Gin性能最强,但不一定每个团队都熟悉Go。如果团队熟悉Python,FastAPI是个绝佳选择,性能好、文档自动生成、异步支持,比Flask更适合有一定规模的项目。Flask更适合极简场景或教学用途。Express在Node生态里依然是首选,特别是全栈JavaScript项目。Spring Boot适合大型企业系统、需要事务管理、ORM和大量依赖注入的场景,启动慢但运行稳。

我自己的习惯是:个人项目用FastAPI,公司新项目偏重性能时用Gin,做原型或短期工具用Flask。Spring Boot只在已有Java技术栈的团队里才会选。

这次实测让我明白一个道理:没有哪个框架是“最好的”,只有“最合适的”。Hello World测试能给你一个基线,但真实业务里数据库查询、缓存、网络IO才是真正的瓶颈。所以选框架时,除了跑这个简单的Hello World,最好用你的真实业务逻辑再压一次。不过在那之前,至少你知道每个框架的基础底子怎么样,心里有数总比瞎猜强。

赞(0)
未经允许不得转载:helloworld官网下载 » 我拿Hello World测了5种Web框架,结果出乎意料