为什么 JavaScript 不支持多线程?
-
09-06-2019 - |
题
这是故意的设计决定还是我们当前浏览器的问题将在未来的版本中得到纠正?
解决方案
JavaScript 不支持多线程,因为浏览器中的 JavaScript 解释器是单线程(AFAIK)。即使是 Google Chrome 也不会让单个网页的 JavaScript 并发运行,因为这会导致现有网页出现大量并发问题。Chrome 所做的就是将多个组件(不同的选项卡、插件等)分离到单独的进程中,但我无法想象单个页面具有多个 JavaScript 线程。
但是,您可以按照建议使用, setTimeout
允许某种调度和“假”并发。这会导致浏览器重新获得对渲染线程的控制,并启动提供给 setTimeout
在给定的毫秒数之后。如果您希望在对其执行操作时允许刷新视口(您所看到的内容),这非常有用。只是循环通过例如坐标并相应地更新元素只会让您看到开始和结束位置,而中间没有任何内容。
我们在 JavaScript 中使用一个抽象库,它允许我们创建由同一个 JavaScript 解释器管理的进程和线程。这允许我们通过以下方式运行操作:
- 进程A,线程1
- 进程A,线程2
- 进程 B,线程 1
- 进程A,线程3
- 进程A,线程4
- 进程 B,线程 2
- 暂停进程A
- 进程 B,线程 3
- 进程 B,线程 4
- 进程 B,线程 5
- 启动进程A
- 进程A,线程5
这允许某种形式的调度并伪造并行性、线程的启动和停止等,但它不会是真正的多线程。我不认为它会在语言本身中实现,因为真正的多线程只有在浏览器可以运行单页多线程(甚至超过一个核心)时才有用,而且那里的困难要大得多比额外的可能性。
对于 JavaScript 的未来,请查看以下内容:https://developer.mozilla.org/presentations/xtech2006/javascript/
其他提示
传统上,JS 旨在编写简短、快速运行的代码。如果您要进行重大计算,您可以在服务器上进行 - JS+HTML 的想法 应用程序 在浏览器中运行很长一段时间做一些不平凡的事情是荒谬的。
当然,现在我们有了。但是,浏览器需要一些时间才能赶上 - 大多数浏览器都是围绕单线程模型设计的,并且改变这一点并不容易。Google Gears 通过要求隔离后台执行来回避许多潜在问题 - 不更改 DOM(因为这不是线程安全的),不访问主线程创建的对象(同上)。虽然有限制性,但这可能是不久的将来最实用的设计,既因为它简化了浏览器的设计,又因为它降低了允许缺乏经验的 JS 编码人员乱搞线程的风险......
@马西奥:
为什么这就是不在 Javascript 中实现多线程的一个原因呢?程序员可以使用他们拥有的工具做任何他们想做的事情。
那么,我们就不要给他们提供如此容易的工具 滥用 我打开的所有其他网站最终都会使我的浏览器崩溃。如果简单地实现这一点,您将直接进入在 IE7 开发过程中让 MS 如此头痛的领域:附加组件作者对线程模型的玩弄得又快又松,导致了隐藏的错误,当主线程上的对象生命周期发生变化时,这些错误就会变得明显。坏的。如果您正在为 IE 编写多线程 ActiveX 附加组件,我想它是随处可见的;但这并不意味着它需要更进一步。
JavaScript 多线程(有一些限制)就在这里。Google 为 Gears 实施了工作器,并且工作器也包含在 HTML5 中。大多数浏览器已经添加了对此功能的支持。
数据的线程安全得到保证,因为与工作线程通信的所有数据都被序列化/复制。
欲了解更多信息,请阅读:
我不知道这个决定的理由,但我知道您可以使用 setTimeout 模拟多线程编程的一些好处。您可以给人一种多个进程同时做事的错觉,但实际上,所有事情都发生在一个线程中。
只需让你的函数做一些工作,然后调用类似的东西:
setTimeout(function () {
... do the rest of the work...
}, 0);
当他们有机会时,任何其他需要做的事情(例如 UI 更新、动画图像等)都会发生。
多线程.js 包装 Web Workers 并允许在 JS 中轻松实现多线程。适用于所有新浏览器,包括 iOS Safari。:)
你的意思是为什么该语言不支持多线程或者为什么浏览器中的 JavaScript 引擎不支持多线程?
第一个问题的答案是,浏览器中的 JavaScript 应该在沙箱中以独立于机器/操作系统的方式运行,添加多线程支持会使语言变得复杂,并将语言与操作系统联系得太紧密。
正如matt b所说,问题不是很清楚。假设您询问该语言的多线程支持:因为当前浏览器中运行的 99.999% 的应用程序都不需要它。如果您确实需要它,有一些解决方法(例如使用 window.setTimeout)。
一般来说,多线程非常、非常、非常、非常、非常、非常难(我有说这很难吗?),除非你施加额外的限制(比如仅使用不可变数据)。
英特尔一直在对 Javascript 中的多线程进行一些开源研究,最近在 GDC 2012 上进行了展示。这是 视频. 。该研究小组使用 OpenCL,主要关注英特尔芯片组和 Windows 操作系统。该项目的代号为 RiverTrail,代码可在 GitHub 上获取
一些更有用的链接:
目前一些浏览器确实支持多线程。因此,如果您需要,可以使用特定的库。例如,查看以下材料:
Node.js 10.5+ 支持 工作线程 作为实验性功能(您可以将其与 --实验工作者 启用标志): https://nodejs.org/api/worker_threads.html
所以,规则是:
- 如果你需要做 I/O 绑定操作, ,然后使用内部机制(又名回调/承诺/异步等待)
- 如果你需要做 CPU 密集型操作, ,然后使用工作线程。
工作线程旨在成为长期存在的线程,这意味着您生成一个后台线程,然后通过消息传递与其进行通信。
否则,如果您需要使用匿名函数执行沉重的 CPU 负载,那么您可以使用 https://github.com/wilk/microjob, ,一个围绕工作线程构建的小型库。
这是不支持多线程的实现。目前,Google Gears 提供了一种通过执行外部进程来使用某种形式的并发性的方法,但仅此而已。
谷歌今天应该发布的新浏览器(Google Chrome)通过在进程中分离来并行执行一些代码。
当然,核心语言可以拥有与 Java 等相同的支持,但对 Erlang 并发性的支持还遥不可及。
据我所知,Google Chrome 将具有多线程 javascript,因此这是一个“当前实现”问题。
根据 本文 JavaScript 线程已经可以实现。
如果没有对线程同步的适当语言支持,尝试新的实现甚至没有意义。现有的复杂 JS 应用程序(例如任何使用 ExtJS 的东西)很可能会意外崩溃,但如果没有 synchronized
关键字或类似的东西,编写行为正确的新程序也将非常困难甚至不可能。
但是,您可以使用 eval 函数在某种程度上实现并发
/* content of the threads to be run */
var threads = [
[
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');",
"document.write('Foo <br/>');"
],
[
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');",
"document.write('Bar <br/>');"
]
];
window.onload = function() {
var lines = 0, quantum = 3, max = 0;
/* get the longer thread length */
for(var i=0; i<threads.length; i++) {
if(max < threads[i].length) {
max = threads[i].length;
}
}
/* execute them */
while(lines < max) {
for(var i=0; i<threads.length; i++) {
for(var j = lines; j < threads[i].length && j < (lines + quantum); j++) {
eval(threads[i][j]);
}
}
lines += quantum;
}
}
你可以使用jetworker,webworker上的包装器https://github.com/uxitten/jetworker
使用 HTML5 带来的 webworkers 显然可以使用 javascript 进行多线程处理。
webworkers 和标准多线程环境之间的主要区别是内存资源不与主线程共享,对对象的引用从一个线程到另一个线程不可见。线程通过交换消息进行通信,因此可以遵循事件驱动的设计模式来实现同步和并发方法调用算法。
许多框架允许在线程之间构建编程,其中包括 OODK-JS,一个支持并发编程的 OOP js 框架https://github.com/GOMServices/oodk-js-oop-for-js