Javascript将SharedArrayBuffer同步到主线程
将Javascript将SharedArrayBuffer同步到主线程,javascript,multithreading,web-worker,Javascript,Multithreading,Web Worker,将SharedArrayBuffer同步到主线程时出现问题 以下是场景: 我有两个工人负责处理我程序的不同方面。第一个工人负责对象交互,第二个工人负责计算可视性等,主线程负责可视化 首先,第一个工人创建一个具有以下布局的SharedArrayBuffer: new SharedArrayBuffer(112); [ Lock: 4 Byte MetaInfo: 4 Byte Location: 12 Byte Scale: 12 Byte
SharedArrayBuffer
同步到主线程时出现问题
以下是场景:
我有两个工人负责处理我程序的不同方面。第一个工人负责对象交互,第二个工人负责计算可视性等,主线程负责可视化
首先,第一个工人创建一个具有以下布局的SharedArrayBuffer
:
new SharedArrayBuffer(112);
[
Lock: 4 Byte
MetaInfo: 4 Byte
Location: 12 Byte
Scale: 12 Byte
Rotation: 16 Byte
Matrix: 64 Byte
]
然后,他将SAB发送给主线程和第二个辅助线程,并将位置比例和旋转属性存储在缓冲区中。每次更新字段时,他都会锁定SAB,更新值并将MetaInfo字段的第一位(转换标志)设置为true
如果设置了变换标志,则第二个工作者将根据给定的位置比例和旋转字段计算矩阵,并将其保存在矩阵字段中。之后,MetaInfo字段的第二位(矩阵标志)将设置为true
如果设置了矩阵标志,主线程现在需要读取最终矩阵
问题来了:在worker上,可以使用lock字段上的Atomics.wait
方法锁定缓冲区。但是主线程缺少这些特性,导致口吃和“跳跃”。是否有一致的方法防止其他员工在阅读过程中写入SAB
以下是我的SharedArrayBuffer
包装器的代码:
class SharedObject {
SharedBuffer: SharedArrayBuffer; // the shared array buffer
Lock: Int32Array; // view for lockíng the buffer
MetaInfo: Int32Array; // view for meta info
Location: Float32Array;
constructor(buffer) {
// if valid buffer is passed assign it to this object
if (buffer !== undefined && buffer instanceof SharedArrayBuffer && buffer.byteLength == 112) {
this.SharedBuffer = buffer;
} else {
// create new shared array buffer
this.SharedBuffer = new SharedArrayBuffer(112);
}
this.Lock = new Int32Array(this.SharedBuffer, 0, 4);
this.MetaInfo = new Int32Array(this.SharedBuffer, 4, 8);
[ ... init the rest of the views ... ]
// init the lock element
if (buffer === undefined) {
Atomics.store(this.Lock, 0, 1);
}
}
lock() {
Atomics.wait(this.Lock, 0, 0);
Atomics.store(this.Lock, 0, 0);
return true;
}
free() {
if (Atomics.wake(this.Lock, 0, 1) == 0) {
Atomics.store(this.Lock, 0, 1);
}
return true;
}
setFlag(flag) {
this.MetaInfo[0] = this.MetaInfo[0] | flag;
}
isFlagSet(flag) {
return (this.MetaInfo[0] & flag) > 0;
}
resetFlag(flag) {
this.MetaInfo[0] = this.MetaInfo[0] - (this.MetaInfo[0] & flag);
}
}
注意:锁定和释放方法不能在主线程中使用,因为:
注意:此操作仅适用于共享Int32Array,不允许在主线程上执行
这个设置甚至可能在一个代码> SharedArrayBuffer < /代码>中有多个独立的字段,或者我应该考虑每个应用程序使用多个<代码> SharedArrayBuffer < /代码>。 在做了一些研究之后,看来防止主线程使用的选择是避免同步线程阻塞,由于主线程处理用户事件和页面呈现以及其他服务,并且允许
Atomics.wait()
将导致web应用程序的用户体验不佳
紧随其后的是,目前还没有在Chrome上实现,但在Firefox上可用
使用屏幕外画布,您可以从用于渲染的web worker中Atomics.wait()
,从共享数组缓冲区读取数据后应用gl
操作,然后调用,这将把gl
帧渲染到主线程
不幸的是,由于Firefox是目前唯一支持OffscreenCanvasAPI的浏览器,而NW.js仅适用于Chromium,由于缺乏对
Atomics.wait()的支持,这种特殊的同步挑战似乎无法克服
和WebGL在Chrome的同一线程中。不要认为问题仍然存在。然而,如果有人面临同样的问题,我的想法如下:
Atomics.wait(this.Lock,0,0);//你是最近才开始这个项目的吗?我看到Chrome在周四推出了对SharedArrayBuffer
的支持,它不支持任何标志。这是个好消息,也许它解决了通过消息端口发送SharedArrayBuffer
的问题。但遗憾的是,我目前正在使用chrome 60的nwjs内部工作。哦,很有趣。。我已经有一段时间没听说过有人使用它了,但我要说的是Chrome 60是第一个官方支持SharedArrayBuffer
的版本。您是否需要使用nwjs,或者您是否能够轻松切换到使用基于浏览器的JavaScript?我们正在构建一个需要一些文件系统交互的应用程序。但是,如果支持WebGL 2和SharedArrayBuffer,则重新定义器应该能够完全在浏览器中运行。var sab=new SharedArrayBuffer(4);var lock=新的Int32Array(sab);原子学。等待(锁定,0,0)代码>结果:VM1347:3未捕获类型错误:在此上下文中不能调用Atomics.wait
Jea我读到了这方面的内容,并进行了一些测试。但是OffscreenCanvas
有很多错误(例如,画布在空闲一秒后消失),正如您所提到的,它只在FF中可用。目前该功能不太好:(还有另一种可能性,您可以查看。有一个名为的同步库,可以使用polyfill促进原子操作。demo/
目录中有演示程序供参考,因为似乎没有非常详尽的文档。1.为什么?我没有实现自己的“锁定机制”但是使用了现有的。2.阻止来自主线程的数据并不意味着没有其他线程正在处理阻止的数据。竞争条件仍然会出现。3.消息有很多开销,并且不适用于实时数据流。4.在我的场景中,每个帧至少需要数百次连续检查3次0帧/秒。开销再次过大。已更新答案。
Atomics.wait(this.Lock, 0, 0); // <-- 2 threads can check 'lock' flag one by one
// and pass to the next line
Atomics.store(this.Lock, 0, 0); // <-- then they both set 0 as a 'lock' flag
// and move further
return true;
}