three.js 中使用多线程以及性能测试
今天郭先生说一下WebWorker以及WebWorker在three.js中的应用。我们都知道Javascript是单线程的,比如执行js代码的同时UI渲染就会停止,对于多核CPU的点脑,这一点让人难以接受,好在Web Worker的出现多少解决了一些问题。官方说Web Worker指的是一种可由脚本创建的后台任务,任务执行中可以向其创建者收发信息。要创建一个 Worker ,只须调用 Worker(URL) 构造函数,函数参数 URL 为指定的脚本。关于Web Worker的更多知识请阅读Web Worker。线案例请点击博客原文。
1. 在three.js中使用多线程
在three.js中使用Web Worker经常发生在大量计算造成CUP阻塞的情况下,我们举一个例子,比如说我们制作了1000个Mesh。

让他们简单的动起来,CPU几乎没有什么压力,FPS会在60左右,但是如果让这1000个Mesh的位置都需要大量计算才能得到,那么FPS就会很低(和计算量成负相关),下面是一段代码
for(let i=0; i<num; i++) {
let angle = positions[i].y / (1000 / (Math.PI * 10));
positions[i].x = positions[i].x + Math.sin(angle);
positions[i].z = positions[i].z + Math.cos(angle);
positions[i].y = positions[i].y + 1;
//上面就是简单的位置变化,下面的代码模拟复杂的变化,累加100000次(这是非常占用线程的情况)
for(let j=1, total=1; j<=100000; j++) {
total += j;
}
if(positions[i].y > 500) {
positions[i].y = positions[i].y - 1000;
}
}
for(var i=0; i<num; i++) {
group.children[i].position.set(positions[i].x, positions[i].y, positions[i].z);
}
positions是储存1000个Mesh位置信息的数组,group里面储存了所有的Mesh,每次渲染都更改positions的位置信息,然后给Group的每一个Mesh设置新值,这种情况下FPS会低至7FPS,转动场景可以很明显的感觉到卡顿。接下来我们使用Web Worker处理这个问题,主线程代码如下
myWorker = new Worker('/static/js/worker.js');
myWorker.postMessage(positions);
myWorker.onmessage = e => {
let positions = e.data;
for(var i=0; i<num; i++) {
group.children[i].position.set(positions[i].x, positions[i].y, positions[i].z);
}
}
脚本代码如下
onmessage = function(e) {
let num = 1000;
let positions = e.data;
setInterval(e => {
for(let i=0; i<num; i++) {
let angle = positions[i].y / (1000 / (Math.PI * 10));
positions[i].x = positions[i].x + Math.sin(angle);
positions[i].z = positions[i].z + Math.cos(angle);
positions[i].y = positions[i].y + 1;
for(let j=1, total=1; j<=100000; j++) {
total += j;
}
if(positions[i].y > 500) {
positions[i].y = positions[i].y - 1000;
}
}
postMessage(positions);
}, 1000 / 60)
};
主要代码和未使用Web Worker几乎一样,只不过是将处理位置的代码放在新的线程中完成,setInterval定时器每一次完成位置计算都会通过postMessage(positions)将位置信息返回给主线程,主线程通过onmessage接受信息,返回对象的data属性就是新的positions。这样一来FPS可以达到60左右,转动场景感觉的到卡顿。这是十分让人欣喜的。
2. 性能分析
前面已经说了在每一次位置计算中做10万次累加,未使用Web Worker的情况下FPS降到了7,下面是更多的数据(数据仅做对比,和当前使用情况以及配合有关)。
| 累加次数(万次) | 使用Web Worker | 未使用Web Worker |
| 1 | 60 | 60 |
| 3 | 60 | 39 |
| 5 | 60 | 26 |
| 7 | 60 | 11 |
| 9 | 60 | 8 |
| 11 | 60 | 6 |
这里面可以看出,不管是多么大量的计算,使用Web Worker都不会影响主线程,但是对于未使用Web Worker影响是十分严重的,下面展示一下两种情况下电脑性能的对比
下面是未使用Web Worker

下面是使用Web Worker

这里可以看出使用更多的线程可以很明显的提升CPU使用率。小伙伴们不妨打开线上案例亲自测试一下。
转载请注明地址:郭先生的博客
three.js 中使用多线程以及性能测试的更多相关文章
- 【worker】js中的多线程
因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情.正好趁着这个机会也加深一下html5中的多线程worker的用法和理解. Worker简介 J ...
- JS中的异步以及事件轮询机制
一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...
- Web worker 与JS中异步编程的对比
0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...
- 【面试篇】寒冬求职季之你必须要懂的原生JS(中)
互联网寒冬之际,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力. 一年前,也许你搞清楚闭包,this,原型链,就能获得认可.但是现在 ...
- js中的异步与同步,解决由异步引起的问题
之前在项目中遇到过好多次因为异步引起的变量没有值,所以意识到了认识js中同步与异步机制的重要性 在单线程的js中,异步代码会被放入一个事件队列,等到所有其他代码执行后再执行,而不会阻塞线程. 下面是j ...
- 关于js中的回调函数callback
来源于:http://www.jianshu.com/p/6bc353e5f7a3 前言 其实我一直很困惑关于js 中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制 ...
- 关于 js 中的回调函数 callback
本文写于1年前 曾经的学习文章如今拿出来分享 前言 其实我一直很困惑关于js中的callback,困惑的原因是,学习中这块看的资料少,但是平时又经常见,偶尔复制一下前人代码,功能实现了也就不再去追其原 ...
- 疯狂Html+CSS+JS 中JS总结
来自:http://mzkmzk.github.io/blog/2015/10/05/amazeing-js/ 0 总结 本书的JS 第一章有讲语法有挺多常见的坑点和原理解释很不错 第二章DOM编程讲 ...
- js中的webworker
js中的webworker webworker的作用类似于java的多线程 以独立文件的形式运行webworker index.html <!DOCTYPE html> <html ...
随机推荐
- 第11.23节 Python 中re模块的搜索替换功能:sub及subn函数
一. 引言 在<第11.3节 Python正则表达式搜索支持函数search.match.fullmatch.findall.finditer>重点介绍了几个搜索函数,除了搜索,re模块也 ...
- 第11.16节 Python正则元字符“()”(小括号)与组(group)匹配模式
一. 什么是组 关于组匹配模式,Python官网上说得比较简单,也没有这个名词,只有组这个名词,老猿查了比较多的资料和做了相关测试之后才理解. 组匹配模式,就是在匹配的正则表达式中使用小括号" ...
- PyQt(Python+Qt)学习随笔:Qt Designer中Action创建的方法
在Qt Designer中,可以两种方法创建Action对象,一种是菜单定义时,一种是单独定义. 一.定义菜单创建Action 在Qt Designer中创建菜单时,如果对应菜单是最终执行的菜单项,则 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中QAbstractButton派生按钮部件的icon属性和iconSize属性
icon属性 icon属性保存按钮上展示的图标,图标的缺省大小由图形界面的样式决定,但可以通过 iconSize 属性进行调整. 图标的几种子属性状态的含义与QWidget的windowIcon属性相 ...
- web网络漏洞扫描器编写
这两天看了很多web漏洞扫描器编写的文章,比如W12scan以及其前身W8scan,还有猪猪侠的自动化攻击背景下的过去.现在与未来,以及网上很多优秀的扫描器和博客,除了之前写了一部分的静湖ABC段扫描 ...
- 【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)
Description 给定一颗 \(n\) 个点的树,带边权. 你可以选出一个包含 \(1\) 顶点的连通块,连通块的权值为连接块内这些点的边权和. 求一种选法,使得这个选法的权值是所有选法中第 \ ...
- Java堆内存中为什么有两个survival区及为什么与年轻代比例是1:1:8?
Java堆内存分为年轻代和老年代,其中,年轻代分为Eden区和survival区,survival又分为fromSurvival和toSurvival. 首先第一个问题:为什么要有Survival区? ...
- python最大几个数和最小几个数(堆排序)
最大几个数和最小几个数 import heapq a = [7, 5, 3, 4, 8, 6, 0] cc = heapq.nsmallest(2, a) #最小的两个数 dd = heapq.nla ...
- Java程序执行过程及内存机制
本讲将介绍Java代码是如何一步步运行起来的,其中涉及的编译器,类加载器,字节码校验器,解释器和JIT编译器在整个过程中是发挥着怎样的作用.此外还会介绍Java程序所占用的内存是被如何管理的:堆.栈和 ...
- gnuplot名词缩写
http://blog.163.com/yucheng_xiao/blog/static/7660019220141017114630822/ with 缩写成 w lt 是 linetype 的缩 ...