在本文中,主要测试并比较了Go—Gin和Rust—Actix之间的多部分文件上传性能。
设置
所有测试都在配备16G内存的 MacBook Pro M1 上执行。
软件版本为:
Go v1.20.5Rust v1.70.0
测试工具是一个基于 libcurl 并使用标准线程的自定义工具,能够发送多部分请求。
资产目录中有 100,000 个文件。每个文件的大小都是确切的 100K。这些文件数量在测试工作线程之间进行分配。同一个文件不会一遍又一遍地上传。工作线程会循环处理分配给它们的文件。一旦它们处理完所有分配的文件,它们就会回到第一个文件重新开始。
每个请求携带两个文件作为多部分请求体。请求的头部和体部大致如下:
// -- Headers {"content-length":"205150","content-type":"multipart/form-data; boundary=------------------------3f6a15690b315b91", } // -- Body --------------------------3f6a15690b315b91 Content-Disposition: form-data; name="files"; filename="45469"Content-Type: application/octet-stream <
> --------------------------3f6a15690b315b91 Content-Disposition: form-data; name="files"; filename="42102"Content-Type: application/octet-stream <> --------------------------3f6a15690b315b91-- 代码 Go package main import ("github.com/gin-gonic/gin""github.com/jaevor/go-nanoid") func main() { dst :="/Users/mayankc/Work/source/perfComparisons/uploads/"canonicID, err := nanoid.Standard(21) if err != nil { panic(err) } router := gin.New() router.POST("/upload", func(c *gin.Context) { form, _ := c.MultipartForm() files := form.File["files"] for _, file := range files { c.SaveUploadedFile(file, dst+canonicID()) } c.Writer.WriteHeader(201) }) router.Run(":3000") } Rust use actix_multipart::{ form::{ tempfile::{TempFile, TempFileConfig}, MultipartForm, } }; use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer, Responder}; use nanoid::nanoid; const BASE_DIR: &str ="/Users/mayankc/Work/source/perfComparisons/uploads/"; #[derive(Debug, MultipartForm)] struct UploadForm { #[multipart(rename ="files")] files: Vec, } async fn save_files( MultipartForm(form): MultipartForm, ) ->Result { for f in form.files { let path = format!("{}{}", BASE_DIR, nanoid!()); f.file.persist(path).unwrap(); } Ok(HttpResponse::Ok()) } #[actix_web::main] async fn main() ->std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(middleware::Logger::default()) .app_data(TempFileConfig::default().directory(BASE_DIR)) .service( web::resource("/upload") .route(web::post().to(save_files)), ) }) .bind(("127.0.0.1", 3000))? .run() .await } Rust代码已在release mode下编译。
结果对10个、50个和100个并发连接执行测试。每个测试总共执行10万个请求。
以下是结果:
结论从结果中使用以下公式生成了一个评分表。对于每个测量,获取获胜的幅度。如果获胜幅度为:
< 5%,不给予任何分数在 5% 和 20% 之间,给予获胜者 1 分在 20% 和 50% 之间,给予获胜者 2 分> 50%,给予获胜者 3 分