网站首页 > 技术文章 正文
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
文章大部分内容来自作者 Daniel Lemire 的文章《Web server ‘hello world’ benchmark : Go vs Node.js vs Nim vs Bun》,部分内容做了修改,欢迎阅读。
前言
如果有现有的应用程序同时希望允许使用 HTTP 对其进行 Web 访问,或者想构建一个小型的专用 Web 应用程序,同时不想使用实际的 Web 服务器(例如 Apache 或 IIS)。
有许多流行的框架可用于编写小型 Web 应用程序。 Go 和 JavaScript (Node.js) 是目前最受欢迎的方案。 比如,Netflix 运行在 Node.js 上, 但是 Uber 从 Node.js 迁移到 Go 以获得更好的性能。 当然,还有一些冷门的技术方案,例如 Nim。
Nim (原名Nimrod),是一种静态类型的命令式编程语言, 它能在不影响运行时效率的情况下为程序员提供强大的功能, Nim语言具有高效、有表现力、优雅等特性
深入不同 Web 服务器性能特征具有一定的挑战性。 本文主要通过一个“hello world”的示例来对比不同的 Web 服务器框架,因为更复杂的应用程序可能运行速度更慢,差距加明显。
不同框架示例
下面是一个极简的 Go 服务器代码示例:
package main
import (
"io"
"fmt"
"log"
"net/http"
)
// 引入模块
func main() {
http.HandleFunc("/simple", func(w http.ResponseWriter, r *http.Request){
io.WriteString(w, "Hello!")
})
// 调用HandleFunc方法
fmt.Printf("Starting server at port 3000\n")
// 监听3000端口号
if err := http.ListenAndServe(":3000", nil); err != nil {
log.Fatal(err)
}
}
下面是一个基础的 JavaScript 服务器示例:
// 使用fastify框架
const f = require('fastify')();
f.get('/simple', async (request) => {
return 'hello';
});
f.listen({ port: 3000 })
// 监听3000端口号
.then(() => console.log('listening on port 3000'))
.catch((err) => console.error(err));
Bun 用于开发、测试、运行和打包 JavaScript 和 TypeScript 项目。 Bun 是一款专为提高速度而设计的一体化 JavaScript 运行时和工具包,配有打包器、测试运行器和与 Node.js 兼容的包管理器。使用 Bun 构建的 Server 示例代码如下:
const server = Bun.serve({
// 调用Bun.serve方法
port: 3000,
fetch(req) {
let url = new URL(req.url);
let pname = url.pathname;
if (pname == '/simple') {
return Response('Hello');
}
return new Response('Not Found.');
},
});
如果是 Nim,可以通过下面代码来完成类似功能:
import options, asyncdispatch
import httpbeast
// 导入相关包
proc onRequest(req: Request): Future[void] =
if req.httpMethod == some(HttpGet):
case req.path.get()
of "/simple":
req.send("Hello World")
else:
req.send(Http404)
run(onRequest, initSettings(port=Port(3000)))
当然,也可以将 uWebSockets.js 与 Node 一起使用。uWebSockets 是一个轻量级的 C++ WebSocket 库,为开发人员提供了构建实时应用程序的高性能且可扩展的解决方案,它的设计速度快、内存效率高并且易于集成到现有项目中。
下面是使用uWebSockets.js的代码示例:
const uWS = require('uWebSockets.js');
// 导入相应的包
const port = 3000;
const app = uWS
.App({})
.get('/simple', (res, req) => {
res.end('Hello!');
})
.listen(port, (token) => {
if (token) {
console.log('Listening to port ' + port);
} else {
console.log('Failed to listen to port ' + port);
}
});
还可以将 C++ 与 lithium 库一起使用。本质上,Lithium 是一组易于使用的 C++ 库,用于编写高性能 HTTP 服务器。
#include <lithium_http_server.hh>
int main() {
li::http_api my_api;
my_api.get("/simple") =
[&](li::http_request& request, li::http_response& response) {
response.write("hello world.");
};
li::http_serve(my_api, 3000);
}
以上代码示例都在一个强大的、基于 IceLake 的 64 核服务器上运行。 通常,此类大型服务器的时钟速度相对较低(基本频率为 2 GHz,最高为 3.2 GHz)。 下面使用一个简单的 bombardier 命令作为基准测试的一部分:
bombardier -c 10 http://localhost:3000/simple
bombardier 是一个 HTTP(S) 基准测试工具,用Go编程语言编写,并使用优秀的 fasthttp 而不是Go的默认http库,因为它具有闪电般的快速性能。
可以将并发连接数增加到 1000 (-c 1000)。最初的测试使用 autocannon,这对于这项任务来说是一个糟糕的选择。 结果表明 Nim 在这个 demo 示例上表现很好。
测试结论
测试用的 Web 服务器几乎不做任何其他工作,所以算是一个极端情况。 同时也没有进行任何额外配置,是“开箱即用”的性能。 此外,测试用的 Web 服务器可能比 Web 开发人员在实践中使用的任何服务器都更强大。
这个结果有相当大的噪音,大多数开发人员不应该完全相信这个数字,也建议尝试自己运行基准测试。不过,我也看了一些博客文章,所有结论都认为 Go 更快:
- 在 Http Server Performance: NodeJS vs. Go 中,Sunavec 发现 Go 比 Node.js 快 34%。 而且基准更加复杂,也可能更加接近现实。
- 在服务器端 I/O 性能:Node vs. PHP vs. Java vs. Go 中,Peabody 发现 Go 的扩展性比 Node.js 和 Java 好得多,PHP 排在最后。 在压力测试中,他们发现 Java 和 Node.js 不相上下,而 Go 的速度是前者的两倍。
- 在性能基准测试:Bun vs. C# vs. Go vs. Node.js vs. Python 中,测试者发现 Bun 和 Go 是赢家,而 Node.js 的运行速度约为一半。 C# 提供中等性能,而 Python 垫底。
然而,将 C、Rust 和 Zig 添加到这个基准测试中可能会更有趣。
关于 C++的解决方案最初遇到了很多困难。 事实证明,使用 Lithium 很简单:最难的部分是确保系统上安装了 OpenSSL 和 Boost。
Lithium 的作者有一个很好的方案,他解释了如何使用带有脚本的 docker 容器来运行 Lithium 服务器。 以这种方式进行意味着不必担心在系统上安装库。 在 Docker 容器中运行服务器是完全合理的,但存在性能开销,因此在基准测试中没有使用此解决方案。
参考资料
https://blog.boot.dev/golang/node-js-vs-go/
https://lemire.me/blog/2023/10/07/web-server-hello-world-benchmark-go-vs-node-js-vs-nim-vs-bun/
https://matt-42.github.io/lithium/
https://medium.com/deno-the-complete-reference/node-js-vs-deno-vs-bun-vs-go-a-re-look-at-the-hello-world-performance-d90b76ad61a5
https://betterprogramming.pub/http-server-performance-nodejs-vs-go-397751e8d275
https://www.toptal.com/back-end/server-side-io-performance-node-php-java-go
https://www.wwt.com/blog/performance-benchmarking-bun-vs-c-vs-go-vs-nodejs-vs-python
猜你喜欢
- 2025-07-24 将机器指令翻译成 JavaScript -- 终极目标
- 2025-07-24 腾讯元宝上线AI编程模式:支持边修改代码边实时预览
- 2025-05-02 Node.js+Puppeteer:新一代动态爬虫利器,高效抓取不再难!
- 2025-05-02 现在可以部署到Web Assembly的6种语言
- 2025-05-02 七爪源码:这是在 Go 中进行实时重新加载的好方法
- 2025-05-02 哪种编程语言又快又省电?有人对比了27种语言
- 2025-05-02 阿里云迎来史上最特殊的员工:工号AI001,精通200 多种编程语言!
- 2025-05-02 使用 WebAssembly 和 Go 编写前端 Web 框架
- 2025-05-02 完全用 Go 编写的 JS 引擎(常用的编写javascript的工具有哪些)
- 2025-05-02 使用Docker和Codeship来装运Node.js应用
- 1517℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 594℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 521℃MySQL service启动脚本浅析(r12笔记第59天)
- 489℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 488℃启用MySQL查询缓存(mysql8.0查询缓存)
- 476℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 456℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 453℃MySQL server PID file could not be found!失败
- 最近发表
-
- PS所有滤镜的说明(六)(ps滤镜详解)
- 5款小白也能用的在线图片编辑器!电商效率飙升就靠它!
- Java变量(java变量有什么作用)
- Java面试常见问题:Java注解(java中的面试题)
- Java编程入门第一课:HelloWorld(java编程从入门到实践)
- Java基础教程:Java继承概述(java里继承的概述)
- java基础之——访问修饰符(private/default/protected/public)
- 如何规划一个合理的JAVA项目工程结构
- 将机器指令翻译成 JavaScript -- 终极目标
- Web 服务器基准测试:Go vs. Node.js vs. Nim vs. Bun
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)