You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。

问题

  1. 我的Rust代码是否存在问题?若有,如何修复以提升性能?
  2. 若代码无问题,该如何优化以获得更好的性能?

内容的提问来源于stack exchange,提问作者Linh Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:08:14