10 javascript multithreading atomic thread-safety
在JavaScript中增量是一个原子操作吗?如果一个线程正在访问++i;,同时另一个线程
开始访问该操作会有任何问题吗?
Pra*_*kar 10
在Javascript中总是一个函数运行到完成,这意味着如果一个函数正在运行而不是它将完全运行,只有在那之后才会调用另一个函数,因此,语句之间没有交错的可能性(但是在java的情况下它是不同的) ,如果你对异步执行感到困惑而不是总是记得async意味着以后不能并行,那么,遇到你的问题,答案是,不,你不会遇到任何问题,它将是全原子操作.
\n\n如果一个线程正在访问
\n++i; 同时另外一个开始访问操作会不会有问题?
对于像这样的简单变量来说,这种情况不会发生,因为 JavaScript 的定义是在任何给定时间在一个领域i中只能有一个活动线程(代理的执行线程)。(“领域” - 粗略地说,是 JavaScript 全局环境及其中的内容,例如变量。)因此,普通变量或对象属性根本不会出现该问题。您的函数在同步运行期间不能被中断;JavaScript 定义了“运行到完成”语义:每当从作业队列中选取一个“作业”(如触发事件处理程序)并执行时,它就会在执行任何其他作业之前运行到完成。(对于函数,逻辑只能在、、 或处暂停,而不能在同步复合算术运算中间暂停。它可以在涉及 的复合算术运算中间暂停。更多相关信息见下文。类似地,对于生成器函数,他们的逻辑暂停在。)asyncawaitreturnthrowawaityield
您唯一需要担心的地方是如果您使用共享内存,实际内存在领域之间共享,因此确实可以同时被多个线程访问。但如果您这样做,您将SharedArrayBuffer使用 a 处理 a 或类型化数组SharedArrayBuffer,而不是简单的变量或属性。但是,是的,如果处理共享内存,您将体验到 CPU 操作重新排序、过时缓存等所有“光荣”乐趣。Atomics这就是我们拥有对象(包括 )的部分原因Atomics.add,它使用共享内存以原子方式向类型化数组中的元素添加值。(但要注意 na\xc3\xafve 的用法!毕竟,另一个线程可能会在您add完成后、在您读取该值之前覆盖该值...这就是为什么Atomics.add返回新值,而您应该使用新值。)Atomics提供了确保安全访问共享内存所需的裸构建块。(有关此内容的更多信息,请参阅我的书《JavaScript:新玩具:“共享内存和Atomics”》的第 16 章。)
注意:这一切都适用于符合规范的标准 JavaScript 引擎,例如 Web 浏览器和 Node.js 中的引擎。非标准 JavaScript 环境,例如 Java 虚拟机中内置的 JavaScript 脚本支持,可以(当然)定义替代的非标准语义。
\nReasync函数:函数中不涉及多线程async。但事实上,函数的逻辑被暂停在 a 处,这await 可能会导致一些令人惊讶的行为。也就是说,它可能发生的地方清楚地标有await。
除非你不得不担心,否则我不会担心下面的细节。但对于那些这样做的人...
\n考虑:
\nlet a = 1;\n\nasync function one() {\n return 1;\n}\n\nasync function example() {\n console.log(`Adding 1 to a`);\n a += await one();\n}\n\nconsole.log(`Start, a = ${a}`);\nPromise.all([\n example(),\n example(),\n example(),\n])\n.then(() => {\n console.log(`All done, a = ${a}`);\n});Run Code Online (Sandbox Code Playgroud)\r\n(从技术上讲,我们可以只使用a += await 1;, 因为await会将其操作数包装在隐含的Promise.resolve(x),但我认为显示实际的承诺会更清楚。)
输出:
\n\n开始,a = 1\na 加 1\na 加 1\na 加 1\n全部完成,a = 2\n\n
但是等等,我们加了 1a3 次,结果应该是 4,而不是 2?!?!
关键在于await这句话里:
a += await one();\nRun Code Online (Sandbox Code Playgroud)\n处理起来是这样的:
\na并将其放在一边;叫它atemp。one并得到它的承诺。addend。atemp + addend。a.或者在代码中:
\n/* 1 */ const atemp = a;\n/* 2 */ const promise = one();\n/* 3 */ const addend = await promise; // Logic is suspended here and resumed later\n/* 4 */ const result = atemp + addend;\n/* 5 */ a = result;\nRun Code Online (Sandbox Code Playgroud)\n(您可以在EvaluateStringOrNumericBinaryExpression中找到此详细信息(您可以在规范中的
\n在我们使用 的地方example,我们调用了它三次,而没有等待它的承诺解决,因此 Step\xc2\xa01 运行了三次,将a(1) 的值保留了三次。然后,使用这些保存的值a覆盖 \ 的值。
生成器函数在 处具有类似的行为yield,其中它们的逻辑被暂停,然后稍后恢复。
同样,不涉及多线程(并且运行到完成完全完整),只是当函数async的逻辑到达await, return(显式或隐式)或 时throw,函数在该点退出并且返回一个承诺。如果这是因为 an await,那么当函数awaited 的承诺解决时,函数的逻辑将继续,并且将(在正常情况下)最终解决async函数返回的承诺。但这些事情中的每一个都会在单个活动线程上完成。
| 归档时间: |
|
| 查看次数: |
3933 次 |
| 最近记录: |