Rust WASM(web_sys)与JavaScript Canvas2D性能问题及优化问询
Rust WASM + web_sys Canvas2D 性能优化问题
我正在使用Rust WASM(基于web_sys)开发一款HTML5 Canvas2D游戏,对执行性能要求较高。测试发现,原生JavaScript调用Canvas2D API的性能优于Rust WASM通过web_sys调用的性能。
JavaScript测试代码及结果
let canvas = document.getElementById("feature"); let context = canvas.getContext("2d"); let image = new Image(); image.src = "/scene_code_origin/maps/lorencia.png"; function drawImage(context, image) { context.clearRect(0.0, 0.0, 2562.0, 1440.0); context.drawImage(image, 0.0, 0.0, 400.0, 400.0, 0.0, 0.0, 2562.0, 1440.0); } function drawCanvas(context) { context.clearRect(0.0, 0.0, 2562.0, 1440.0); context.beginPath(); // Draw the outer circle. context .arc(75.0, 75.0, 50.0, 0.0, Math.PI * 2.0); // Draw the mouth. context.moveTo(110.0, 75.0); context.arc(75.0, 75.0, 35.0, 0.0, Math.PI); // Draw the left eye. context.moveTo(65.0, 65.0); context .arc(60.0, 65.0, 5.0, 0.0, Math.PI * 2.0); // Draw the right eye. context.moveTo(95.0, 65.0); context .arc(90.0, 65.0, 5.0, 0.0, Math.PI * 2.0); context.strokeStyle = "white"; context.stroke(); } function test() { let a = []; for (i = 0; i < 10; i++) { let start = performance.now(); // console.log("the current time (in ms) is " +start); for (x = 0; x < 1000000; x++) { drawCanvas(context); // drawImage(context, image); } let end = performance.now() - start; // console.log("performance: " + end); a.push(end); } // Calculate the sum of the float values let sum = a.reduce((a, b) => a + b, 0); // Get the count of elements in the vector let count = a.length; // Check if the vector is not empty if (count > 0) { // Calculate the average value let average = sum / count; // Print the average value alert("Average performance value: " + average); } else { // Print a message if the vector is empty console.log("The vector is empty."); } }
测试结果:drawCanvas()函数平均耗时2066.8ms,drawImage()函数平均耗时1428.4ms。
Rust测试代码及结果
fn draw_canvas(context: &CanvasRenderingContext2d) { context.clear_rect(0.0, 0.0, 2562.0, 1440.0); context.begin_path(); // Draw the outer circle. context .arc(75.0, 75.0, 50.0, 0.0, std::f64::consts::PI * 2.0) .unwrap(); // Draw the mouth. context.move_to(110.0, 75.0); context.arc(75.0, 75.0, 35.0, 0.0, std::f64::consts::PI).unwrap(); // Draw the left eye. context.move_to(65.0, 65.0); context .arc(60.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) .unwrap(); // Draw the right eye. context.move_to(95.0, 65.0); context .arc(90.0, 65.0, 5.0, 0.0, std::f64::consts::PI * 2.0) .unwrap(); context.set_stroke_style(&JsValue::from_str("white")); context.stroke(); } fn draw_image(context: &CanvasRenderingContext2d, image: &HtmlImageElement) { context.clear_rect(0.0, 0.0, 2562.0, 1440.0); context.draw_image_with_html_image_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh (image, 0.0, 0.0, 400.0, 400.0, 0.0, 0.0, 2562.0, 1440.0); } ------------------- running code -------------------- let document = web_sys::window().unwrap().document().unwrap(); let canvas = document.get_element_by_id("feature").unwrap(); let canvas: web_sys::HtmlCanvasElement = canvas .dyn_into::<web_sys::HtmlCanvasElement>() .map_err(|_| ()) .unwrap(); let context = canvas .get_context("2d") .unwrap() .unwrap() .dyn_into::<web_sys::CanvasRenderingContext2d>() .unwrap(); let window = web_sys::window().expect("should have a window in this context"); let performance = window .performance() .expect("performance should be available"); let mut a: Vec<f64> = Vec::new(); let image_container = IMAGE_CONTAINER.borrow(); let image = &image_container.get("maps/lorencia.png").unwrap().as_ref().image; for _ in 1..10 { let start = performance.now(); // log!("the current time (in ms) is {}", start); for _ in 1..1000000 { draw_canvas(&context); // draw_image(&context, image); } let end = performance.now() - start; // log!("performance: {}", end); a.push(end); } // Calculate the sum of the float values let sum: f64 = a.iter().sum(); // Get the count of elements in the vector let count = a.len(); // Check if the vector is not empty if count > 0 { // Calculate the average value let average = sum / count as f64; // Print the average value log!("Average performance value: {}", average); alert(&format!("Average performance value: {}", average)); } else { // Print a message if the vector is empty log!("The vector is empty."); }
测试结果:默认编译下drawCanvas()耗时5303.2ms、drawImage()耗时2699.4ms;开启release模式(lto=true,opt-level=3)后,drawCanvas()耗时3137.4ms、drawImage()耗时1665.1ms,但仍慢于JavaScript。
问题
- 我的Rust代码是否存在问题?若有,如何修复以提升性能?
- 若代码无问题,该如何优化以获得更好的性能?
内容的提问来源于stack exchange,提问作者Linh Nguyen
相关产品推荐
相关产品推荐

