我把文件重新编码后,加载速度提升300%!(下)

简介: 我把文件重新编码后,加载速度提升300%!

原始代码涉及到一些PCD文件头处理等工作,由于这一部份和业务强相关,和本文所聊的压缩关系不大,所以我就把相关代码删了,只留下二进制转码相关的核心代码。

代码很短,应该不难看懂吧?看不懂的评论区举个手,我来给你手摸手教学下。

懒得看或者看不懂的,我作为课代表帮大家把关键点挑出来了,一起看看吧:

1. DataView2. CreateWriteStream

3. Buffer.from(dataview.buffer)

我先帮大家捋一捋整体流程,大致如下:

image.png

为什么我们没有用理想操作模型呢?两个文件流pipe一下,中间加一个转换器做一个编解码,搞定!多简单呀。

那是因为,当前这个场景不合适。

ThreeJS天然支持PCD文件的渲染,但前提是,必须有标准头,也就是这个东西。

image.png

有了头部元信息之后,剩下的部分就是「点云二进制」数据,ThreeJS天然支持。可以看下对应的源码:(https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/PCDLoader.js

image.png

既然如此,那我们就可以把一个带有标准头的二进制文件直接丢给ThreeJS去渲染即可,ThreeJS会在运行时去解析,我们无需在服务端或者前端做多余的「解码」操作,节约渲染成本。

而如果采用理想模型,这意味着我们在转码Stream的每一个chunk的时候,是直接将chunk转成了二进制,并没有按「」为单位的去处理,毕竟NodeJS的chunk是按某个固定字节大小来分片的,而不是定制化的按「点」为分片单位。

这样的话,最终转出来的,仅仅是一个二进制文件,而不是一个ThreeJS可以识别的「点云二进制」文件,我们就必须在渲染之前先处理一遍数据,这就不太合适了。

当然了,如果是那么简单就能做的,也就不会有今天这篇文章了,也是因为这个特殊的处理场景,引入了一些比较有意思的知识点,所以才想分享给大家。

首先想想我们为什么要用DataView?DataView又是什么?一起看下MDN的解释:

DataView 视图是一个可以从二进制 ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序(endianness)问题。

我们需要以「」为单位做编码,写入文件,那么也就是说,我们需要操作文件Buffer,而NodeJS为了防止安全和内存泄漏问题,是不允许直接操作Buffer本身的,于是提供了一个DataView接口,非常方便的操作ArrayBuffer

我们可以将每个「点」的信息逐一写入DataView:


point.forEach((axis, axisIndex) => {
  dataview.setFloat32(rowIndex * POINT_BYTES_SIZE + axisIndex * PARAMS_LENGTH, Number(axis), true)
})

这里我们用了setFloat32 ,因为xyzi四个参数每个都是4字节的浮点数,所以用float32来存,第一个参数是位偏移量,第二个是需要存的值,第三个是字节序(可选)。


dataview.setFloat32(byteOffset, value [, littleEndian])

对所有的点逐一处理之后,我们就拿到了一个存有完整点云信息的DataView,就可以拿去写文件了!

But!这里又有关键点了。你以为直接拿DataView的Buffer写入文件即可,如下:


wstream.write(dataview.buffer)

然后你就会看到报错:

image.png

为什么呢?

DataView的Buffer难道不是Buffer么?还真不是!你把鼠标挪到代码上一看:

image.png

好家伙,是个ArrayBuffer!没错,官方文档一开始就说了,DataView就是拿来操作ArrayBuffer的,没毛病。

那么怎么处理呢?其实稍微改一下就好啦:


wstream.write(Buffer.from(dataview.buffer))

Buffer.from 就可以直接把buffer转出来。

你可能有疑问了,从arrayBuffer转buffer我会了,那反过来呢?哈哈,其实一开始我们读源文件拿来做点云信息解析的时候,就已经这么干了,被我省略了代码,这里补上:


const inputData = fs.readFileSync(input)
const ab = inputData.buffer.slice(inputData.byteOffset, inputData.byteOffset + inputData.byt

看到没有,读取文件数据后,我们拿到的是一个buffer,而从buffer转arrayBuffer,只需要一个小小的slice即可,是不是很神奇。

到这里,其实我帮大家挑出来的关键点就都扯清楚了,最后还剩一个疑问,为啥要用createWriteStream 来写文件?有什么特殊考虑吗?

没错,其实一开始是想着,用「流」来写文件,性能更好,不会占用大量内存空间

但是上面也说了,我们不能简单的对接两头文件流,必须得把「」数据读出来逐个编码,那么势必就需要产生Buffer占用空间了,这样的话,Stream其实就变鸡肋了,完全可以直接替换成 fs.writeFileSync,而且writeFile还可以直接写DataView,更省事了呢!


fs.writeFileSync(output, dataview)

帮大家总结一下今天的几个小知识点:

1. NodeJS提供了一个DataView,用来操作Buffer,确切的说是 ArrayBuffer。

2. Buffer和ArrayBuffer可以互相转换。

3. Stream可以节约Buffer占用内存空间,但如果不利用好pipe,就等于失去了它的优势,还不如直接file操作。


啦!今天的分享就到这了,你学废了吗?

相关实践学习
基于Hologres轻量实时的高性能OLAP分析
本教程基于GitHub Archive公开数据集,通过DataWorks将GitHub中的项⽬、行为等20多种事件类型数据实时采集至Hologres进行分析,同时使用DataV内置模板,快速搭建实时可视化数据大屏,从开发者、项⽬、编程语⾔等多个维度了解GitHub实时数据变化情况。
阿里云实时数仓实战 - 用户行为数仓搭建
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3 )前置知识要求:熟练掌握 SQL 语法熟悉 Linux 命令,对 Hadoop 大数据体系有一定的了解   课程大纲 第一章 了解数据仓库概念 初步了解数据仓库是干什么的 第二章 按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章 数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章 采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章 用户行为数据仓库 严格按照企业的标准开发 第六章 搭建业务数仓理论基础和对表的分类同步 第七章 业务数仓的搭建  业务行为数仓效果图  
目录
相关文章
|
Java 程序员
收藏!阿里毕玄16篇文章,深度讲解Java开发、系统设计、职业发展
阿里毕玄结合自己的经历深度讲解Java开发、系统设计、职业发展等问题,快来一键收藏吧。
35128 1
|
安全 应用服务中间件 nginx
Nginx限制IP访问只允许特定域名访问
为了我们的服务器安全,我们需要禁止直接使用 IP 访问我们的服务器,我们可以借助 Nginx 完成
1634 1
Nginx限制IP访问只允许特定域名访问
|
8月前
|
安全 Linux 开发工具
【Azure 环境】Azure 虚拟机上部署 DeepSeek R1 模型教程(1.5B参数)【失败】
遇见错误一:operator torchvision::nms does not exist 遇见错误二:RuntimeError: Failed to infer device type
550 22
|
运维 Kubernetes 调度
阿里云容器服务 ACK One 分布式云容器企业落地实践
3年前的云栖大会,我们发布分布式云容器平台ACK One,随着3年的发展,很高兴看到ACK One在混合云,分布式云领域帮助到越来越多的客户,今天给大家汇报下ACK One 3年来的发展演进,以及如何帮助客户解决分布式领域多云多集群管理的挑战。
阿里云容器服务 ACK One 分布式云容器企业落地实践
|
12月前
|
存储 前端开发 JavaScript
useRef 钩子使用技巧
【10月更文挑战第12天】本文详细介绍了 React 中的 `useRef` Hook,包括其基础概念、基本用法、常见问题与易错点以及如何避免这些问题。通过具体代码示例,解释了 `useRef` 的应用场景,如保存对 DOM 元素的引用、保存回调函数和定时器 ID 等,帮助开发者更有效地使用这一工具。
386 14
|
网络安全
mac下通过ssh脚本实现免账号密码连接运服务器
mac下通过ssh脚本实现免账号密码连接运服务器
149 3
|
机器人
小红书自动化仿写发文机器人了解一下
小红书自动化仿写发文机器人了解一下
453 2
|
JavaScript API
Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
这篇博客文章讲解了Vue中列表排序的方法,使用`filter`、`sort`和`indexOf`等数组方法进行数据的过滤和排序,并探讨了Vue检测数据变化的原理,包括Vue如何通过setter和数组方法来实现数据的响应式更新。
Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
|
JSON 前端开发 Java
前端axios传参总结
该文介绍了在前后端分离的开发中,前端使用axios向后端Spring传递参数的两种主要方法。针对@RequestParam注解,推荐使用params传参,将参数格式化为x-www-form-urlencoded,或者使用FormData和qs.stringify。对于@RequestBody,Axios的data传参默认为JSON格式,直接传入对象即可。
378 0
|
关系型数据库 PostgreSQL
postgresql字符串拼接语法
【5月更文挑战第6天】postgresql字符串拼接语法
598 0