Python、JavaScript和Rust的Web效能比較 - Alex

banq發表於2021-12-15

Python使用FastApi測試;Node.JS使用Fastify;Rust則使用Actix。
選擇的Python和Node框架,是在搜尋 "最快的<某語言>api "時得到的最高結果;Rust的Actix是一直高度維護的。

測試的基礎很簡單;在我的MacBook Pro M1上,每個框架處理來自網路伺服器的5000個基本 "Hello, World "響應需要多長時間?

我用來執行測試的程式碼非常簡單,顯然,我們只關心速度:
 

Python

客戶端程式碼:
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

MAX_RETIES = 3

def create_retriable_session():
    s = requests.Session()
    retries = Retry(
        total=MAX_RETIES,
    )
    s.mount('http://', HTTPAdapter(max_retries=retries))
    s.mount('https://', HTTPAdapter(max_retries=retries))
    return s


def main():
    s = create_retriable_session()

    for _ in range(0, 5000):
        s.get("http://127.0.0.1:8000/")


伺服器端,使用fastapi:

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}

執行伺服器:
uvicorn main:app
測試結果:

5.22 s ± 221 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


下面是使用另外一個框架Fastfy使用非同步後的程式碼:

const fastify = require('fastify')({logger: false})

const PORT = 8000;

fastify.get('/', async (request, reply) => {
    return {message: 'Hello World'}
})

const start = async () => {
    try {
        await fastify.listen(PORT)
    } catch (err) {
        fastify.log.error(err)
        process.exit(1)
    }
}
start()



再次測試結果:

4.49 s ± 84.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


比較結果:
FastApi每秒處理約957.85次,Fastfy每秒處理1113.59次。
  

Rust

use actix_web::{App, get, HttpResponse, HttpServer, Responder};

#[get("/")]
async fn hello() -> impl Responder {
    HttpResponse::Ok().body("{\"message\": \"Hello World\"}")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(hello)
    })
        .bind("127.0.0.1:8000")?
        .run()
        .await
}


測試結果:

4.32 s ± 58.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


比較結果:
我們再次看到,Rust比python快,也比Fastify快,Rust能夠每秒處理1157.41個請求,每秒比Fastify快44個請求,比FastApi每秒快200個請求。
   

Node.js
只是為了好玩,Express是最常見的節點框架,所以我也想測試一下,Express比fastify的功能更全面,所以我估計它也會更慢。

const express = require('express')
const app = express()
const port = 8000

app.get('/', (req, res) => {
    res.json({message: "Hello World"})
})

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

 
測試結果:

4.88 s ± 152 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


而且確實比fastify要慢。
  

結論
Rust絕對是最快的選擇,但它是最好的嗎?我不確定我是否能回答這個問題,因為98%的情況下這要取決於。你的團隊知道什麼?該框架有你需要的功能嗎?如果沒有,你能建立它嗎?如果你沒有一個專家團隊,學習起來有多容易?該框架在4-5年記憶體在的可能性有多大?
這些測試有一些注意事項,它們是在Python中執行的,所以它們只能以Python發出請求的速度執行,而且它們不是多執行緒的,所以框架也可能不會使用多執行緒來響應,這取決於Python請求庫中的會話工作方式。另外,一般來說,node是單執行緒的,node用佇列來偽造併發,但是有一種方法可以解決這個問題,那就是用workers,它允許你在不同的執行緒上執行多個伺服器,這取決於CPU有多少邏輯核心,這在生產中非常有用,因為它有巨大的效能提升,但同樣,這些測試不能從中受益。
這篇文章的重點不是讓你轉到Actix/Rust的生產伺服器上,重點是展示我在學習新東西時喜歡的一種簡單的方法,並希望展示測試並不總是要嚴肅或複雜。
 

相關文章