从WebWorker同步获取数据?
Obtain data synchronously from WebWorker?
虽然我知道 JavaScript 本质上是单线程的并且通常不赞成这样的事情,但我想知道是否有任何方法可以让 WebWorker 等待直到主线程提供一些数据不破坏 WebWorker 的调用堆栈。
由于这是一个有趣的项目,我可以使用新技术和在旧浏览器上 运行 不可靠的东西,我不介意深奥的 hack,只要它们有效。
我想到的其他一些解决方案:
循环不断地轮询LocalStorage,直到预定key处有数据。这似乎可行,因为即使在循环中轮询时,其他线程对 LocalStorage 的更新也应该对当前线程可见,从所有 discussions 关于 LocalStorage 线程安全的判断以及多个选项卡写入同一个 LocalStorage 键.这种方法的缺点是它不是真正的 "waiting",即工作线程仍然消耗 LocalStorage 上的全部 CPU 使用锤击。虽然 LocalStorage 通常是用锁实现的,但不可能长时间持有 LocalStorage 锁(锁释放一次 getItem
或 setItem
returns)。
ECMAScript 6 yield
。这在这里不起作用,因为它需要将调用堆栈中的所有函数(直到您要屈服的地方)标记为生成器函数。我要暂停我的 WebWorker 的地方有一个包含 WebAssembly 函数的调用堆栈,不能将其标记为生成器函数。
索引数据库。这不起作用,因为 IndexedDB 不支持同步请求。
我知道 this 类似的问题,但该问题专门讨论了 onmessage
事件,并且在 yield
和 WebAssembly 被引入之前的 2012 年被问及。
有没有办法以某种方式模拟 WebWorker 线程上的锁,或者以其他方式,以便等待某些数据可用?
编辑:请注意 SharedArrayBuffer
是 disabled by default in all major browsers (on January 5th 2018) in response to Spectre, and hasn't been fully re-enabled yet。
JavaScript 的 SharedArrayBuffer 听起来非常适合您:
- 新技术:刚刚 在 1 月份的 TC39 会议上进入了第 4 阶段(及时赶上 ES2017)
- 在旧版浏览器上 运行 不可靠(旧版有不同的 API,或者没有可用的实现)
- 深奥的技巧(similar to the C++ memory model)
- 有效
出于您的目的,您希望 WebWorker 等待数据可用。使用 SharedArrayBuffer
你可以使用自旋循环(Atomics.load
直到值改变)但是最好使用 Atomics.wait
until the other worker sends you an Atomics.notify
. This later API is heavily inspired by Linux's futex 并且如果你正在等待的值不是'可用。
// Main program:
var w = new Worker("worker.js")
var sab = new SharedArrayBuffer(1024);
w.postMessage(sab);
var i = new Int32Array(sab);
// Maybe wait for worker.js to message back that it's ready through onmessage?
//
// Fill i with some data!
// ...
//
// Notify one worker, at location 0, with value 1.
Atomics.store(i, 0, 1);
Atomics.notify(i, 0, /* notify count */ 1);
// worker.js:
var sab;
var i;
onmessage = function (ev) {
sab = ev.data;
var i = new Int32Array(sab);
}
// Maybe tell the main program we're ready through postMessage?
//
// ...
// Wait until location 0 isn't value 0
Atomics.wait(i, 0, 0);
记住:阻塞主线程是个坏主意!如果您这样做,您的网站将没有响应。您的问题是询问有关阻止工人的问题,但读者可能对从主线程等待感兴趣。不要!
非常相似且兼容,API 将 eventually be available in WebAssembly. Here's an early draft proposal。当我说兼容时:我们希望 WebAssembly 能够使用与 JavaScript 相同的 SharedArrayBuffer
,并且两者都能够通过它进行无缝通信。
虽然我知道 JavaScript 本质上是单线程的并且通常不赞成这样的事情,但我想知道是否有任何方法可以让 WebWorker 等待直到主线程提供一些数据不破坏 WebWorker 的调用堆栈。
由于这是一个有趣的项目,我可以使用新技术和在旧浏览器上 运行 不可靠的东西,我不介意深奥的 hack,只要它们有效。
我想到的其他一些解决方案:
循环不断地轮询LocalStorage,直到预定key处有数据。这似乎可行,因为即使在循环中轮询时,其他线程对 LocalStorage 的更新也应该对当前线程可见,从所有 discussions 关于 LocalStorage 线程安全的判断以及多个选项卡写入同一个 LocalStorage 键.这种方法的缺点是它不是真正的 "waiting",即工作线程仍然消耗 LocalStorage 上的全部 CPU 使用锤击。虽然 LocalStorage 通常是用锁实现的,但不可能长时间持有 LocalStorage 锁(锁释放一次
getItem
或setItem
returns)。ECMAScript 6
yield
。这在这里不起作用,因为它需要将调用堆栈中的所有函数(直到您要屈服的地方)标记为生成器函数。我要暂停我的 WebWorker 的地方有一个包含 WebAssembly 函数的调用堆栈,不能将其标记为生成器函数。索引数据库。这不起作用,因为 IndexedDB 不支持同步请求。
我知道 this 类似的问题,但该问题专门讨论了 onmessage
事件,并且在 yield
和 WebAssembly 被引入之前的 2012 年被问及。
有没有办法以某种方式模拟 WebWorker 线程上的锁,或者以其他方式,以便等待某些数据可用?
编辑:请注意 SharedArrayBuffer
是 disabled by default in all major browsers (on January 5th 2018) in response to Spectre, and hasn't been fully re-enabled yet。
JavaScript 的 SharedArrayBuffer 听起来非常适合您:
- 新技术:刚刚 在 1 月份的 TC39 会议上进入了第 4 阶段(及时赶上 ES2017)
- 在旧版浏览器上 运行 不可靠(旧版有不同的 API,或者没有可用的实现)
- 深奥的技巧(similar to the C++ memory model)
- 有效
出于您的目的,您希望 WebWorker 等待数据可用。使用 SharedArrayBuffer
你可以使用自旋循环(Atomics.load
直到值改变)但是最好使用 Atomics.wait
until the other worker sends you an Atomics.notify
. This later API is heavily inspired by Linux's futex 并且如果你正在等待的值不是'可用。
// Main program:
var w = new Worker("worker.js")
var sab = new SharedArrayBuffer(1024);
w.postMessage(sab);
var i = new Int32Array(sab);
// Maybe wait for worker.js to message back that it's ready through onmessage?
//
// Fill i with some data!
// ...
//
// Notify one worker, at location 0, with value 1.
Atomics.store(i, 0, 1);
Atomics.notify(i, 0, /* notify count */ 1);
// worker.js:
var sab;
var i;
onmessage = function (ev) {
sab = ev.data;
var i = new Int32Array(sab);
}
// Maybe tell the main program we're ready through postMessage?
//
// ...
// Wait until location 0 isn't value 0
Atomics.wait(i, 0, 0);
记住:阻塞主线程是个坏主意!如果您这样做,您的网站将没有响应。您的问题是询问有关阻止工人的问题,但读者可能对从主线程等待感兴趣。不要!
非常相似且兼容,API 将 eventually be available in WebAssembly. Here's an early draft proposal。当我说兼容时:我们希望 WebAssembly 能够使用与 JavaScript 相同的 SharedArrayBuffer
,并且两者都能够通过它进行无缝通信。