首页 > 其他分享 >Cesium之Web Workers

Cesium之Web Workers

时间:2023-04-25 15:22:08浏览次数:55  
标签:Web worker Workers Worker JS 线程 Cesium

1. 引言

多线程是编程中常用的方法,例如,在桌面程序中,主线程一般是UI线程,负责UI绘制与用户交互,而运算处理往往是交给背后的工作线程,这样可以有效避免交互时的卡顿感

浏览器是多进程的,每打开一个网页,都会开启一个渲染进程,渲染进程包含:

  • GUI渲染线程 (有且只有一个)
  • JS引擎线程 (有且只有一个)
  • 事件触发线程
  • 定时器触发线程
  • 异步http请求线程

其中,JS引擎线程就是解析JS代码的线程,由于JS引擎线程有且只有一个,所以JS代码执行是单线程的(笔者注:异步函数是使用任务队列实现的,除非调用了其他线程的函数,如定时器等,不然异步函数还是单线程执行的)

GUI渲染线程与JS引擎线程是互斥的,且JS引擎线程会先执行,如果JS代码卡住会导致GUI绘制卡住

有关浏览器架构与原理,可以参考:

Web Workers就是创建JS代码执行的线程,使得JS代码执行能以多线程的方式执行,避免JS引擎线程卡住

有关Web Workers的解释可以参考:

本文描述浏览器中的Web Workers并基于Cesium源码进行举例

2. Web Workers

通常而言,Web Workers包含:

  • 专用线程(Dedicated Workers)
  • 共享线程(Shared Workers)
  • 后台线程(Service Workers)等

这里主要是记述通常使用的专用线程(Dedicated Workers)

Web Worker的大致的使用方法如下:

(在主线程里)创建一个Web Worker

const worker = new Worker('WebWorkerTest.js')
  • WebWorkerTest.js是Web Worker执行的JS代码文件
  • 加载Web Worker执行的JS代码文件需要使用HTTP或HTTPS协议,即,需要搭建网络服务器

(在主线程里)向创建的Web Worker发送数据

worker.postMessage([2, 3])

(在子线程Web Worker,即WebWorkerTest.js中)接收主线程的数据、处理并发送给主线程

onmessage = function(e) {
    console.log('Message received from main script')
    const workerResult = e.data[0] * e.data[1]
    console.log('Posting message back to main script')
    postMessage(workerResult)
}

(在主线程里)接收Web Worker发送的数据

worker.onmessage = (e) => {
      console.log("Result:", e.data)
    }

综上,此处创建了两个文件:WebWorkerTest.jsWebWorkerTest.html

WebWorkerTest.html代码如下:

<body>
  <script>
    const worker = new Worker('WebWorkerTest.js')
    worker.postMessage([2, 3])
    worker.onmessage = (e) => {
      console.log("Result:", e.data)
    }
  </script>
</body>

WebWorkerTest.js代码如下:

onmessage = function(e) {
    console.log('Message received from main script')
    const workerResult = e.data[0] * e.data[1]
    console.log('Posting message back to main script')
    postMessage(workerResult)
}

运行结果如下(使用VS Code和Live Server插件):

image-20230425142342609

更详细的Web Worker的使用方法,可以参考以下文档:

3. Cesium中的Web Workers

Cesium源码中,对Web Workers进行了封装,封装为TaskProcessor

源码中给出的TaskProcessor使用示例为:

const taskProcessor = new Cesium.TaskProcessor('myWorkerPath');
const promise = taskProcessor.scheduleTask({
    someParameter : true,
    another : 'hello'
});
if (!Cesium.defined(promise)) {
    // too many active tasks - try again later
} else {
    promise.then(function(result) {
        // use the result of the task
    });
}

查看源码,可以知道taskProcessor.scheduleTask()函数为:

TaskProcessor.prototype.scheduleTask = function (parameters, transferableObjects) {
  // ...
  this._worker = createWorker(this);
  return Promise.resolve(canTransferArrayBuffer()).then(function (
    canTransferArrayBuffer
  ) {
    processor._worker.postMessage(
      {
        id: id,
        parameters: parameters,
        canTransferArrayBuffer: canTransferArrayBuffer,
      },
      transferableObjects
    );

    return deferred.promise;
  });
};

createWorker()函数为

function createWorker(processor) {
  const worker = new Worker(getBootstrapperUrl());
  worker.postMessage = defaultValue(
    worker.webkitPostMessage,
    worker.postMessage
  );
  // ...
  return worker;
}

不难看出,Cesium中将Web Workers封装成了Promise,既有操作Promise的优雅,又有调用Web Workers带来的多线程优势

例如,在Scene\Primitive.js中,使用TaskProcessor创建Geometry

先是使用createGeometry.js的文件名创建TaskProcessor

if (!defined(createGeometryTaskProcessors)) {
    createGeometryTaskProcessors = new Array(numberOfCreationWorkers);
    for (i = 0; i < numberOfCreationWorkers; i++) {
        createGeometryTaskProcessors[i] = new TaskProcessor("createGeometry");
    }
}

然后创建promise数组:

promises.push(
    createGeometryTaskProcessors[i].scheduleTask(
        {
            subTasks: subTasks[i],
        },
        subTaskTransferableObjects
    )
);

最后使用Promise.all方法执行所有任务并等待结果返回:

Promise.all(promises)
    .then(function (results) {
    primitive._createGeometryResults = results;
    primitive._state = PrimitiveState.CREATED;
})
    .catch(function (error) {
    setReady(primitive, frameState, PrimitiveState.FAILED, error);
});

4. 参考资料

[1] Web Workers API - Web API 接口参考 | MDN (mozilla.org)

[2] Web Worker 使用教程 - 阮一峰的网络日志 (ruanyifeng.com)

[3] Cesium原理篇:4Web Workers剖析 - fu*k - 博客园 (cnblogs.com)

[4] 浏览器的进程与线程--深入同步、异步问题 - 知乎 (zhihu.com)

[5] Web Worker 之全面讲解 - 知乎 (zhihu.com)

[6] 使用 Service Worker - Web API 接口参考 | MDN (mozilla.org)

标签:Web,worker,Workers,Worker,JS,线程,Cesium
From: https://www.cnblogs.com/jiujiubashiyi/p/17352716.html

相关文章

  • [Web app] 笔记
    如何回收应用池1.找到需要回收的webapp2.找到“应用服务编辑器(预览版)”,打开编辑器3.找到web.config文件,可以随意添加一点注释或修改任何内容,自动保存后即可进行应用池回收 ......
  • JavaWeb回顾与小结(二)
    AjaxAjax介绍概念AsynchronousJavaScriptAndXML,异步的JS和XML作用数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术原生Ajax准备数据地址创建XMLHttpRequest对象:......
  • (完结篇)Python web框架FastAPI——一个比Flask和Tornada更高性能的API 框架
    今日鸡汤借问酒家何处有,牧童遥指杏花村。0前言    前几天给大家分别分享了(入门篇)简析Pythonweb框架FastAPI——一个比Flask和Tornada更高性能的API框架和(进阶篇)Pythonweb框架FastAPI——一个比Flask和Tornada更高性能的API框架。今天欢迎大家来到FastAPI系列分享的完结篇......
  • Cesium加载ArcGIS Server4490且orgin -400 400的切片服务
    Cesium在使用加载Cesium.ArcGisMapServerImageryProvider加载切片服务时,默认只支持wgs84的4326坐标系,不支持CGCS2000的4490坐标系。如果是ArcGIS发布的4490坐标系的切片服务,如果原点在orginX:-180.0Y:90.0的情况下,我们可以通过WebMapTileServiceImageryProvider按照WMTS的方式......
  • web工程启航
    前言每天都在使用springboot随便copy过来一个直接使用那么是否真正的具备工程能力吗?idea2021jkd8mvn3.6.3阿里云OS用简单的材料一步一步,回顾下每天用的springboot工程如何来的。简单web工程简单web,不连接任何数据库,只需要提供能够提供rest服务即可。创建一个web工......
  • ctfshow web入门 sql注入 web 183-186
    web183-web186涉及盲注,不管是时间盲注还是布尔盲注,若用手工,会非常耗时,通常使用脚本重点:​ 1、了解python脚本编写​ 2、了解条件语句(where、having)区别​ 3、了解sql语句位运算符​ 4、了解mysql特性​ 5、扩展了解简单爬虫目录web183web184web185web186web183//拼......
  • 面试最常问的数组转树,树转数组 c++ web框架paozhu实现
    刚毕业同学,找工作常被问二维数组转树,树转二维数组需要支持无限层级实现,如果你了解这个语言那么实现起来还要一番思考c++web框架paozhu使用需要实现数据库表数据到前台菜单实现,就是这种功能二维数组转树,树转二维数组保存时候树二维数组,展示时候树树状。这个技术难点在于无......
  • kubectl 命令 --save-config 将部署信息添加到注解,防止deploy或webhook通过注释添加
    1、--save-config为什么需要使用kubctlapply保存配置?kubectl apply<file.yaml>--save-config创建或更新部署,并将部署另存为元数据。文件上说--save-config[=false]:如果为true,则当前对象的配置将保存在其注释中。当您将来要对此对象执行kubectlapply时,这非常有用。为什么......
  • WebSphere Message Broker -JavaCompute组件的使用
      IBMWebSphereMessageBrokerJavaCompute节点的使用. importjava.util.List;importcom.ibm.broker.javacompute.MbJavaComputeNode;importcom.ibm.broker.plugin.*;publicclassSub_FFN_JavaComputeextendsMbJavaComputeNode{ privatefinalArticleCreator......
  • 轮询、长轮询和websocket
    轮询从字面意思理解,轮询是不断的询问服务器然后获取资源的一种方式,可以解决像多次TCP连接造成的服务器堵塞(但是多次发送http请求也会浪费服务器资源)。长轮询长轮询是轮询的一种变种,我理解的是轮询相当于是每隔一个时间去发送http请求询问数据,长轮询会根据情况去决定间隔的时......