华人澳洲中文论坛

热图推荐

    Webassembly 实战

    [复制链接]

    2022-9-1 07:28:09 24 0

    配景
    名目中使用Canvas绘图,有一个笔刷功用,后端会给前端mask编码的数据,前端需求转成ImageData,能力绘制到Canvas上,这个转换至关耗时,以后是放在worker里计算,而后再前往ImageData渲染,当mask得多、很大的状况时,仍是会存在机能问题,一方面内存占用过大、一方面是履行时间太长。有无优化的空间?
    比来看了一本对于Rust的书籍,想看一下基于Rust的Webassembly机能咋样,因而首先想到了mask的功用,先在这个功用试验一下,假如还不错,能够推行到其它场景,Canvas的得多底层操作都对比耗机能,假如能用wasm,乃至能够媲美原生客户端。此外未来产品也有可能推出客户端版本,或许基于Tauri的客户端版本也是一种选择,能够做一些技术贮备。
    数据比较
    通过苦楚的重构(Rust的语法真的太难了...),终于把mask转换的代码重构为wasm,并接入Vimo,看看一下数据如何:
    形容
    mask示例
    worker机能
    wasm机能
    阐明
    mask数量少、尺寸小




    均匀:30ms
    request耗时很高




    均匀
    mask尺寸很小的状况下,wasm的机能远远超过worker
    mask数量多、尺寸大




    三张图片,分别是:8155ms、2215ms、5309ms


    三张图片,分别是:1606ms、373ms、783ms
    mask数量多,尺寸也较大的状况下,wasm的机能是worker的4倍以上
    mask尺寸大




    同一张图片测试两次,均匀15000ms


    同一张图片测试两次,均匀2250ms
    mask尺寸超大的状况,wasm机能是worker的6倍
    初步论断
    转换机能:mask的机能在各种场景下都优于worker,机能最少晋升4倍以上,当mask很小时,机能是worker的30倍。
    内存占用:内存占用不太好测试,用阅读器的Performance简略测试了一下,wasm的内存占用也比worker的小。
    技术调研Worker 计划
    将一个mask绘制到界面次要有两个步骤,这两个步骤都对比耗时,第一步是转换,将mask转成imageData,这一步是纯计算的,会放在worker外面,第二步是绘制,下列只关注转换这一步,第二步暂不关注(虽然它也很慢,还存在可优化的空间)。
    因为worker是异步的,转化分为三个小步骤:
    postMessage to worker ,这一步将需求转换的mask传给workerGenerate ImageData,这一步将mask转成ImageData,像素点操作,机能问题次要泛起在这一步骤postMessage to brower,这一步将转换好的ImageData传回给阅读器,而后就能绘制啦!


    与worker交互,数据需求序列化、反序列化,当对象很大时,是很耗机能的,如下的例子就能充沛阐明,不论mask多大,postMessage to worker这一步会花不少时间,实际上mask转行是很快(1毫秒摆布),但往返的传输就很慢了


    Webassembly 摹拟worker计划
    重构为Wasm的初版版本,我选择跟worker相似的计划,只是用rust完成罢了,也是分三个小步骤:
    mask_data to JsValue,与wasm交互,动静一样需求序列化Generate ImageData,mask转换,跟worker逻辑同样image_data to JsValue,将image_data序列化后给到阅读器


    论断:实际测试上去,最初一步将image_data序列化很耗时,整体时间乃至比worker的还慢,所以此计划废弃了。
    Webassembly 同享内存计划
    数据序列化和反序列化通常很耗时,那有无计划绕过它?谜底就是同享内存,这也是wasm保举的做法之一,与wasm交互时,数据只要一份且存在wasm的memory对象中,阅读器间接读取wasm中内存数据并渲染,无需额定空间,三个小步骤
    Write mask to share memory,将需求转换的数据写入wasm内存,再也不经过序列化传给wasm了Generate ImageData,从内存读取mask数据并转成ImageData,并将ImageData写入share memory,再也不经过序列化传给阅读器Read ImageData from share memory,阅读器间接读取wasm内存,并绘制,无需再结构对象


    阐明:下面的测试数据就是基于这个计划完成的,实际上还有优化空间,内存还能够优化一下,时间瓜葛就没做了。
    Webassembly 多线程计划
    下面的计划还没彻底利用wasm的劣势,mask转换是能够并发的,那末能否用并发去转换mask呢?
    wasm原生还不反对异步(据说有方案反对),想在阅读器跑多线程,目前只要worke能做到了,咱们能够跑多个woker,在每个worker外面再去调用wasm,这样在mask数量得多的状况下,利用多线程,机能又能晋升不少


    阐明:名目还未完成,github上有一个使用wasm + woker做多线程的例子,能够关上去体验下:http://github.com/jsdw/wasm-fractal
    One More Thing
    以后是把一切mask转成imageData之后再一致渲染(draw)的,当mask得多、很大的时分,有可能会由于内存占用过量而致使阅读器卡死,对比好的解决计划是分片渲染,也即边转换、边绘制,这样用户体验也会好得多(虽然整体时间其实不会增加)。重构后的wasm计划,反对分片渲染会更灵敏,由于它是每一个个mask独自转换,能够灵敏管制,内存及时回收,阅读器不易崩掉(以后的worker是批量转换的)
    除了mask这一步能够用wasm完成以外,绘制是不是也能够呢,我以为只有波及到少量像素点操作的,应该均可有用wasm,固然啦,这所有还要斟酌开发本钱。
    参考
    Setup - Rust and WebAssembly入门 Rust 开发 WebAssemblyrustwasm.github.io

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    返回列表 本版积分规则

    :
    注册会员
    :
    论坛短信
    :
    未填写
    :
    未填写
    :
    未填写

    主题25

    帖子34

    积分163

    图文推荐