rust / go / python / php CPU,IO,MYSql压测
结论: Go综合性能最强
实现三种最常用的接口:
/cpu 模拟CPU密集型计算(递归计算斐波那契数列第35项),用于测试计算性能。
/io 模拟IO密集型操作(异步sleep 100ms),用于测试IO性能。
/mysql 实现基本的select查询
用压力测试工具ab 对这两个接口进行请求,即可查看响应时间和性能表现
- -n 100 表示总共请求100次
- -c 10 表示并发10个请求
Rust
使用axum框架,代码:
main.rs
// 引入相关依赖 use axum::{Router, routing::get, response::Html, response::IntoResponse, extract::State}; use std::net::SocketAddr; use std::time::Instant; use tokio::time::{sleep, Duration}; use std::sync::Arc; use sqlx::mysql::MySqlPoolOptions; use sqlx::MySqlPool; use rand::Rng; use serde::Serialize; use md5; use serde_json; #[tokio::main] async fn main() { // 创建 MySQL 连接池 let db_url = "mysql://root:guestR56Y@114.66.52.123:56841/uranmac?charset=utf8mb4"; let pool = MySqlPoolOptions::new() .max_connections(5) .connect(db_url) .await .expect("数据库连接失败"); let app = Router::new() .route("/", get(hello_world)) .route("/cpu", get(cpu_bound)) // 计算密集型接口 .route("/io", get(io_bound)) .route("/mysql", get(mysql_test)) // MySQL查询速度测试接口 .with_state(Arc::new(pool)); // 监听地址 let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); println!("服务已启动: http://{}", addr); // 创建 TcpListener let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); // 启动服务 axum::serve(listener, app).await.unwrap(); } // 处理函数 async fn hello_world() -> Html<&'static str> { Html("<h1>Hello, Axum!</h1>") } // 计算密集型处理函数,模拟实际业务逻辑 async fn cpu_bound() -> impl IntoResponse { let start = Instant::now(); // 1. 生成10000条模拟订单数据 #[derive(Serialize)] struct Order { order_id: String, amount: f64, user: String, } let mut rng = rand::thread_rng(); let mut orders = Vec::with_capacity(10_000); for i in 0..10_000 { orders.push(Order { order_id: format!("ORD{}", 100_000 + i), amount: rng.gen_range(10.0..1000.0), user: format!("user_{}", rng.gen_range(1..=1000)), }); } // 2. 过滤金额大于100的订单 let mut filtered: Vec<_> = orders.into_iter().filter(|o| o.amount > 100.0).collect(); // 3. 按金额降序排序 filtered.sort_by(|a, b| b.amount.partial_cmp(&a.amount).unwrap()); // 4. 计算总金额 let total: f64 = filtered.iter().map(|o| o.amount).sum(); // 5. 对前10个订单号做md5哈希 let hashes: Vec<String> = filtered.iter().take(10) .map(|o| format!("{:x}", md5::compute(o.order_id.as_bytes()))) .collect(); // 6. 序列化部分结果为JSON let json_preview = serde_json::to_string(&filtered.iter().take(3).collect::<Vec<_>>()).unwrap_or_default(); let elapsed = start.elapsed(); Html(format!( "<h2>CPU密集型业务逻辑测试完成</h2>\ <p>订单总数: 10000</p>\ <p>过滤后订单数: {}</p>\ <p>总金额: {:.2}</p>\ <p>前10订单号哈希: {:?}</p>\ <p>部分订单示例: {}</p>\ <p>耗时: {:?}</p>", filtered.len(), total, hashes, json_preview, elapsed )) } // IO密集型处理函数,模拟异步IO操作 async fn io_bound() -> impl IntoResponse { let start = Instant::now(); // 异步sleep 100ms,模拟IO密集型任务 sleep(Duration::from_millis(100)).await; let elapsed = start.elapsed(); Html(format!( "<h2>IO密集型任务完成</h2><p>耗时: {:?}</p>", elapsed )) } // MySQL 查询速度测试接口 async fn mysql_test(State(pool): State<Arc<MySqlPool>>) -> impl IntoResponse { let start = Instant::now(); let row = sqlx::query("select company_name from fa_uran_companyinfo where credit_code ='91320114MADW3NT54M'") .fetch_optional(&*pool) .await; let elapsed = start.elapsed(); match row { Ok(Some(_)) => Html(format!("<h2>MySQL查询成功</h2><p>耗时: {:?}</p>", elapsed)), Ok(None) => Html(format!("<h2>未查到数据</h2><p>耗时: {:?}</p>", elapsed)), Err(e) => Html(format!("<h2>查询出错: {}</h2>", e)), } }
Cargo.toml
[package] name = "axum-hello" version = "0.1.0" edition = "2024" [dependencies] axum = "0.8.4" tokio = { version = "1", features = ["full"] } sqlx = { version = "0.7", features = ["mysql", "runtime-tokio-rustls"] } rand = "0.9.1" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" md5 = "0.7.0"
运行: cargo run
CPU压测10并发1000次: ab -n 1000 -c 10 http://127.0.0.1:3000/cpu
结果1:每次请求用时 0.12秒, 总用时2.44秒 ,每秒410次请求, 请求失败654
IO压测10并发1000次:ab -n 1000 -c 10 http://127.0.0.1:3000/io
结果2: 每次请求用时 0.104 秒, 总用时11秒 ,每秒90次请求, 请求失败110
mysql压测10并发1000次: ab -n 1000 -c 10 http://127.0.0.1:3000/mysql
结果3: 每次请求用时0.13秒, 用时33秒 ,每秒30次请求 , 请求失败106
PYTHON:
from fastapi import FastAPI from fastapi.responses import HTMLResponse import time import asyncio import aiomysql import random, json, hashlib import logging logging.getLogger("uvicorn.access").disabled = True app = FastAPI() @app.get("/", response_class=HTMLResponse) async def hello_world(): # 首页,返回简单的 HTML return "<h1>Hello, world!</h1>" @app.get("/cpu", response_class=HTMLResponse) async def cpu_bound(): start = time.perf_counter() # 1. 生成10000条模拟订单数据 orders = [ { "order_id": f"ORD{100000 + i}", "amount": random.uniform(10, 1000), "user": f"user_{random.randint(1, 1000)}" } for i in range(10000) ] # 2. 过滤金额大于100的订单 filtered = [o for o in orders if o["amount"] > 100] # 3. 按金额降序排序 filtered.sort(key=lambda x: x["amount"], reverse=True) # 4. 计算总金额 total = sum(o["amount"] for o in filtered) # 5. 对前10个订单号做哈希 hashes = [hashlib.md5(o["order_id"].encode()).hexdigest() for o in filtered[:10]] # 6. 序列化部分结果为JSON json_preview = json.dumps(filtered[:3], ensure_ascii=False) elapsed = time.perf_counter() - start return ( f"<h2>CPU密集型业务逻辑测试完成</h2>" f"<p>订单总数: {len(orders)}</p>" f"<p>过滤后订单数: {len(filtered)}</p>" f"<p>总金额: {total:.2f}</p>" f"<p>前10订单号哈希: {hashes}</p>" f"<p>部分订单示例: {json_preview}</p>" f"<p>耗时: {elapsed:.6f} 秒</p>" ) @app.get("/io", response_class=HTMLResponse) async def io_bound(): # 记录开始时间 start = time.perf_counter() # 异步sleep 100ms,模拟IO密集型任务 await asyncio.sleep(0.1) elapsed = time.perf_counter() - start # 返回耗时 return f"<h2>IO密集型任务完成</h2><p>耗时: {elapsed:.6f} 秒</p>" @app.get("/mysql", response_class=HTMLResponse) async def mysql_test(): start = time.perf_counter() try: conn = await aiomysql.connect( host='114.66.52.123', port=56841, user='root', password='guestR56Y', db='uranmac', charset='utf8mb4', autocommit=True ) async with conn.cursor() as cur: await cur.execute("select company_name from fa_uran_companyinfo where credit_code ='91320114MADW3NT54M'") result = await cur.fetchone() await conn.ensure_closed() elapsed = time.perf_counter() - start if result: return f"<h2>MySQL查询成功</h2><p>耗时: {elapsed:.6f} 秒</p>" else: return f"<h2>未查到数据</h2><p>耗时: {elapsed:.6f} 秒</p>" except Exception as e: return f"<h2>查询出错: {e}</h2>"
使用fastapi框架:
运行: uvicorn fastpython:app --host 127.0.0.1 --port 3000
CPU压测10并发10次: ab -n 10 -c 10 http://127.0.0.1:3000/cpu
结果1:每次请求用时0.01秒, 总用时17秒, 每秒58次请求, 请求失败0
IO压测10并发1000次:ab -n 1000 -c 10 http://127.0.0.1:3000/io
结果2: 每次请求用时0.11秒, 用时11秒 ,每秒86次请求, 请求失败0
mysql压测10并发1000次: ab -n 1000 -c 10 http://127.0.0.1:3000/mysql
结果3: 每次请求用时0.21秒, 用时18秒 ,每秒54次请求, 请求失败0
Go语言:
package main import ( "context" "crypto/md5" "database/sql" "encoding/json" "fmt" "sort" "time" _ "github.com/go-sql-driver/mysql" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() // 首页 app.Get("/", func(c *fiber.Ctx) error { return c.SendString("<h1>Hello, Fiber!</h1>") }) // 计算密集型接口 app.Get("/cpu", func(c *fiber.Ctx) error { start := time.Now() // 1. 生成10000条模拟订单数据 type Order struct { OrderID string `json:"order_id"` Amount float64 `json:"amount"` User string `json:"user"` } orders := make([]Order, 0, 10000) for i := 0; i < 10000; i++ { orders = append(orders, Order{ OrderID: fmt.Sprintf("ORD%d", 100000+i), Amount: 10 + (990 * float64(i%10000) / 9999), // 10~1000均匀分布 User: fmt.Sprintf("user_%d", 1+i%1000), }) } // 2. 过滤金额大于100的订单 filtered := make([]Order, 0, len(orders)) for _, o := range orders { if o.Amount > 100 { filtered = append(filtered, o) } } // 3. 按金额降序排序 sort.Slice(filtered, func(i, j int) bool { return filtered[i].Amount > filtered[j].Amount }) // 4. 计算总金额 total := 0.0 for _, o := range filtered { total += o.Amount } // 5. 对前10个订单号做哈希 hashes := make([]string, 0, 10) for i := 0; i < 10 && i < len(filtered); i++ { h := md5Sum(filtered[i].OrderID) hashes = append(hashes, h) } // 6. 序列化部分结果为JSON jsonPreview, _ := json.Marshal(filtered[:min(3, len(filtered))]) elapsed := time.Since(start) return c.SendString(fmt.Sprintf( "<h2>CPU密集型业务逻辑测试完成</h2>"+ "<p>订单总数: %d</p>"+ "<p>过滤后订单数: %d</p>"+ "<p>总金额: %.2f</p>"+ "<p>前10订单号哈希: %v</p>"+ "<p>部分订单示例: %s</p>"+ "<p>耗时: %v</p>", len(orders), len(filtered), total, hashes, string(jsonPreview), elapsed, )) }) // IO密集型接口 app.Get("/io", func(c *fiber.Ctx) error { start := time.Now() time.Sleep(100 * time.Millisecond) elapsed := time.Since(start) return c.SendString(fmt.Sprintf("<h2>IO密集型任务完成</h2><p>耗时: %v</p>", elapsed)) }) // MySQL查询速度测试接口 app.Get("/mysql", func(c *fiber.Ctx) error { start := time.Now() // 数据库连接配置 dsn := "root:guestR56Y@tcp(114.66.52.123:56841)/uranmac?charset=utf8mb4" db, err := sql.Open("mysql", dsn) if err != nil { return c.SendString(fmt.Sprintf("<h2>数据库连接失败: %v</h2>", err)) } defer db.Close() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() row := db.QueryRowContext(ctx, "select company_name from fa_uran_companyinfo where credit_code ='91320114MADW3NT54M'") var dummy interface{} err = row.Scan(&dummy) elapsed := time.Since(start) if err == sql.ErrNoRows { return c.SendString(fmt.Sprintf("<h2>未查到数据</h2><p>耗时: %v</p>", elapsed)) } else if err != nil { return c.SendString(fmt.Sprintf("<h2>查询出错: %v</h2>", err)) } return c.SendString(fmt.Sprintf("<h2>MySQL查询成功</h2><p>耗时: %v</p>", elapsed)) }) app.Listen(":3000") } // 工具函数:md5哈希 func md5Sum(s string) string { return fmt.Sprintf("%x", md5.Sum([]byte(s))) } // 工具函数:取最小值 func min(a, b int) int { if a < b { return a } return b }
go run main.go
CPU压测10并发1000次: ab -n 1000 -c 10 http://127.0.0.1:3000/cpu
结果1:每次请求用时0.002秒, 总用时0.7秒, 每秒1497次请求, 请求失败85
IO压测10并发1000次:ab -n 1000 -c 10 http://127.0.0.1:3000/io
结果2: 每次请求用时0.10秒, 用时10秒 ,每秒98次请求, 请求失败106
mysql压测10并发1000次: ab -n 1000 -c 10 http://127.0.0.1:3000/mysql
结果3: 每次请求用时0.21秒, 用时21秒 ,每秒47次请求, 请求失败109
PHP
<?php // index.php // 路由分发 $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); if ($path === '/') { echo "<h1>Hello, PHP!</h1>"; } elseif ($path === '/cpu') { $start = microtime(true); // 1. 生成10000条模拟订单数据 $orders = []; for ($i = 0; $i < 10000; $i++) { $orders[] = [ 'order_id' => 'ORD' . (100000 + $i), 'amount' => 10 + (990 * ($i % 10000) / 9999), // 10~1000均匀分布 'user' => 'user_' . (1 + $i % 1000), ]; } // 2. 过滤金额大于100的订单 $filtered = array_filter($orders, function($o) { return $o['amount'] > 100; }); $filtered = array_values($filtered); // 重新索引 // 3. 按金额降序排序 usort($filtered, function($a, $b) { return $b['amount'] <=> $a['amount']; }); // 4. 计算总金额 $total = array_sum(array_column($filtered, 'amount')); // 5. 对前10个订单号做哈希 $hashes = []; for ($i = 0; $i < 10 && $i < count($filtered); $i++) { $hashes[] = md5($filtered[$i]['order_id']); } // 6. 序列化部分结果为JSON $jsonPreview = json_encode(array_slice($filtered, 0, min(3, count($filtered))), JSON_UNESCAPED_UNICODE); $elapsed = microtime(true) - $start; echo "<h2>CPU密集型业务逻辑测试完成</h2>" . "<p>订单总数: " . count($orders) . "</p>" . "<p>过滤后订单数: " . count($filtered) . "</p>" . "<p>总金额: " . number_format($total, 2) . "</p>" . "<p>前10订单号哈希: [" . implode(", ", $hashes) . "]</p>" . "<p>部分订单示例: $jsonPreview</p>" . "<p>耗时: {$elapsed} 秒</p>"; } elseif ($path === '/io') { $start = microtime(true); usleep(100000); // 100ms $elapsed = microtime(true) - $start; echo "<h2>IO密集型任务完成</h2><p>耗时: {$elapsed}s</p>"; } elseif ($path === '/mysql') { $start = microtime(true); $mysqli = new mysqli("114.66.52.123", "root", "guestR56Y", "uranmac", 56841); if ($mysqli->connect_errno) { echo "<h2>数据库连接失败: {$mysqli->connect_error}</h2>"; exit; } $sql = "select credit_code from fa_uran_companyinfo where credit_code ='91320114MADW3NT54M'"; $result = $mysqli->query($sql); $elapsed = microtime(true) - $start; if ($result && $result->num_rows > 0) { echo "<h2>MySQL查询成功</h2><p>耗时: {$elapsed}s</p>"; } elseif ($result) { echo "<h2>未查到数据</h2><p>耗时: {$elapsed}s</p>"; } else { echo "<h2>查询出错: {$mysqli->error}</h2>"; } $mysqli->close(); } else { http_response_code(404); echo "Not Found"; } // 递归斐波那契 function fibonacci($n) { if ($n === 0) return 0; if ($n === 1) return 1; return fibonacci($n - 1) + fibonacci($n - 2); }
php -S 0.0.0.0:3000
CPU压测10并发10次: ab -n 10 -c 10 http://127.0.0.1:3000/cpu
结果1:每次请求用时0.009秒, 总用时10秒, 每秒100次请求, 请求失败798
IO压测10并发100次:ab -n 1000 -c 10 http://127.0.0.1:3000/io
结果2: 每次请求用时0.10秒, 用时10秒 ,每秒9次请求, 请求失败10
mysql压测10并发100次: ab -n 1000 -c 10 http://127.0.0.1:3000/mysql
结果3: 每次请求用时0.16秒, 用时13秒 ,每秒7次请求, 请求失败8
浙公网安备 33010602011771号