我有一个与“主线程”共享一个 SharedArrayBuffer 的 Worker。为了正常工作,我必须确保在主线程访问 SAB 之前,worker 可以访问它。(编辑:创建工人的代码必须在一个单独的函数中(EDIT2:它返回一个指向 SAB 的数组)。)(也许,这已经不可能了,你会告诉我的)。
初始代码如下所示:
function init() {
var code = `onmessage = function(event) {
console.log('starting');
var buffer=event.data;
var arr = new Uint32Array(buffer);// I need to have this done before accessing the buffer again from the main
//some other code, manipulating the array
}`
var buffer = new SharedArrayBuffer(BUFFER_ELEMENT_SIZE);
var blob = new Blob([code], { "type": 'application/javascript' });
var url = window.URL || window.webkitURL;
var blobUrl = url.createObjectURL(blob);
var counter = new Worker(blobUrl);
counter.postMessage(buffer);
let res = new Uint32Array(buffer);
return res;
}
function test (){
let array = init();
console.log('main');
//accessing the SAB again
};
worker 代码总是在 after 之后执行test()
,控制台总是显示main
then starting
。
使用超时没有帮助。考虑以下代码test
:
function test (){
let array = [];
console.log('main');
setTimeout(function(){
array = initSAB();
},0);
setTimeout(function(){
console.log('main');
//accessing the SAB again
},0);
console.log('end');
};
控制台end
首先显示,然后是main
,然后是starting
。
但是,即使没有超时,将缓冲区分配给 test() 函数之外的全局数组也可以完成这项工作。
我的问题如下:
- 为什么发送消息后工作人员不直接启动(=收到?)。AFAIK,工人有自己的事件队列,所以他们不应该依赖主堆栈变空?
- 是否有详细说明工人在发送消息后何时开始工作的规范?
- 有没有办法在不使用全局变量的情况下再次访问 SAB 之前确保工作人员已经启动?(可以使用忙等待,但我要小心......)可能没有办法,但我想确定一下。
编辑
更准确地说:
- 在完全并行运行的场景中,Worker 将能够在消息发布后立即对其进行处理。显然情况并非如此。
- 大多数浏览器 API(而 Worker 就是这样一个 API)使用回调队列来处理对 API 的调用。但是如果应用了这个,消息将在执行超时回调之前发布/处理。
- 更进一步:如果我尝试在 postMessage 之后通过从 SAB 读取直到它更改一个值来忙等待,则会无限地阻塞程序。对我来说,这意味着浏览器 在调用堆栈为空之前不会 发布消息据我所知,这种行为没有记录在案,我无法解释。
总结一下:如果 postMessage 的调用在函数内部,我想知道浏览器如何确定何时发布消息并由工作人员处理。我已经找到了一种解决方法(全局变量),所以我对它在幕后的工作方式更感兴趣。但是,如果有人可以向我展示一个可行的示例,我会接受它。
编辑2:
使用全局变量的代码(运行良好的代码)如下所示
function init() {
//Unchanged
}
var array = init(); //global
function test (){
console.log('main');
//accessing the SAB again
};
它打印starting
,然后打印main
到控制台。
还值得注意的是:如果我使用 Firefox 浏览器(Chrome 未测试)调试代码,我会在没有全局变量(之前)的情况下得到我想要的结果有人可以解释吗?starting
main