- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我在 the JavaScript spec 中没有看到任何内容, proposed DOM spec extensions与 SharedArrayBuffer
相关,或 current WHAT-WG HTML spec建议当一个线程向另一个线程发布消息并且另一个线程处理该消息时,共享内存将跨线程同步/更新。 (之后一个已经将共享内存发送给另一个。)但是,我也无法通过实验验证它不会发生(在我的测试中,我没有看到过时的值)。是否有这样的保证我失踪了,如果有,它在哪里保证?例如,它是否记录了 postMessage
而我错过了它,或者是否有关于返回事件循环/作业队列的东西来保证它(因为处理来自另一个线程的消息涉及这样做), ETC。?或者,是否绝对不保证(并且该信息在某处的规范中)?
请不要推测或做出“合理猜测”。我正在寻找确凿的信息:来自规范来源的引用,表明它不能保证的可复制实验(尽管我想这是否只是一个实现错误的问题),诸如此类。
以下是我尚未能够捕获未同步内存的测试的源代码。要运行它,您需要使用当前支持 SharedArrayBuffer
的浏览器,我认为目前这意味着 Chrome v67 或更高版本(Firefox、Edge 和 Safari 都支持但在2018 年 1 月对 Spectre 和 Meltdown 的响应;Chrome 也做了,但在 v67 [2018 年 7 月] 中在启用了站点隔离功能的平台上重新启用了它。
sync-test-postMessage.html
:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Sync Test postMessage</title>
</head>
<body>
<script src="sync-test-postMessage-main.js"></script>
</body>
</html>
sync-test-postMessage-main.js
:
const array = new Uint32Array(new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT));
const worker = new Worker("./sync-test-postMessage-worker.js");
let counter = 0;
const limit = 1000000;
const report = Math.floor(limit / 10);
let mismatches = 0;
const now = performance.now();
const log = msg => {
console.log(`${msg} - ${mismatches} mismatch(es) - ${performance.now() - now}ms`);
};
worker.addEventListener("message", e => {
if (e.data && e.data.type === "ping") {
++counter;
const value = array[0];
if (counter !== value) {
++mismatches;
console.log(`Out of sync! ${counter} !== ${value}`);
}
if (counter % report === 0) {
log(`${counter} of ${limit}`);
}
if (counter < limit) {
worker.postMessage({type: "pong"});
} else {
console.log("done");
}
}
});
worker.postMessage({type: "init", array});
console.log(`running to ${limit}`);
sync-test-postMessage-worker.js
:
let array;
this.addEventListener("message", e => {
if (e.data) {
switch (e.data.type) {
case "init":
array = e.data.array;
// fall through to "pong"
case "pong":
++array[0];
this.postMessage({type: "ping"});
break;
}
}
});
使用该代码,如果内存未同步,我希望主线程在某个时候看到共享数组中的陈旧值。但完全有可能(在我看来)这段代码只是碰巧起作用,因为消息传递涉及相对较大的时间尺度......
最佳答案
TL;DR:是的,确实如此。
在the thread on es-discuss ,共享内存提案的作者 Lars Hansen 写道:
In a browser, postMessage send and receive was always intended to create a synchronization edge in the same way a write-read pair is. http://tc39.github.io/ecmascript_sharedmem/shmem.html#WebBrowserEmbedding
Not sure where this prose ended up when the spec was transfered to the es262 document.
我跟进了:
Thanks!
Looks like it's at least partially here: https://tc39.github.io/ecma262/#sec-host-synchronizes-with
So, a question (well, two questions) just for those of us not deeply versed in the terminology of the Memory Model section. Given:
- Thread A sends a 1k shared block to Thread B via
postMessage
- Thread B writes to various locations in that block directly (not via
Atomics.store
)- Thread B does a
postMessage
to Thread A (without referencing the block in thepostMessage
)- Thread A receives the message and reads data from the block (not via
Atomics.load
)...am I correct that in Step 4 it's guaranteed that thread A will reliably see the writes to that block by Thread B from Step 2, because the
postMessage
was a "synchronization edge" ensuring (amongst other things) that CPU L1d caches are up-to-date, etc.?Similarly, if (!) I'm reading it correctly, in your Mandlebrot example, you have an
Atomics.wait
on a single location in a shared block, and when the thread wakes up it seems to assume other data in the block (not in thewait
range) can reliably be read directly. That's also a "synchronization edge"?
他回答说:
...ensuring (amongst other things) that CPU L1d caches are up-to-date, etc.?
是的,这就是该语言的意图。对内存的写入应该发生在 postMessage 之前,而接收消息应该发生在读取之前。
... That's also a "synchronization edge"?
是的,同样的论点。写入发生在唤醒之前,而等待的唤醒发生在读取之前。
所有这一切都是有意为之,以便允许使用廉价的非同步写入和读取来写入和读取数据,然后进行(相对昂贵的)同步以确保适当的可观察性。
关于javascript - `postMessage` 或屈服于事件循环或类似的同步共享内存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52445807/
我对现代JavaScript(ES8)有点陌生。异步产生的首选方法是什么,即使用await在事件循环的某些将来迭代中继续执行脚本?我看到了以下选项: async function yield1() {
我有一个 Duck 类,它有一个生成 block 的 initialize 方法: class Duck def initialize() if block_given? yi
我目前正在学习 F#,我非常喜欢 yield! (yield-bang) 运算符。不仅因为它的名字,当然也因为它的作用。 yield! 运算符基本上允许您从序列表达式中产生序列的所有元素。这对于组合枚
我是一名优秀的程序员,十分优秀!