为什么JavaScript不支持多线程?

这是一个深思熟虑的设计决定,还是我们当前浏览器的一个问题,这个问题将在未来的版本中得到纠正?

191515 次浏览

据我所知,谷歌Chrome将有多线程javascript,所以这是一个“当前实现”的问题。

你的意思是为什么语言不支持多线程,或者为什么浏览器中的JavaScript引擎不支持多线程?

第一个问题的答案是,浏览器中的JavaScript是在沙盒中运行的,以一种独立于机器/操作系统的方式运行,添加多线程支持会使语言变得复杂,并将语言与操作系统联系得太紧密。

它的实现不支持多线程。目前谷歌Gears提供了一种通过执行外部进程来使用某种形式的并发的方法,但仅此而已。

新的浏览器谷歌应该今天发布(谷歌Chrome)通过在进程中分离一些代码并行执行。

当然,核心语言可以提供与Java相同的支持,但对Erlang并发性之类的支持还远远不够。

我不知道这个决定的基本原理,但我知道可以使用setTimeout模拟多线程编程的一些好处。您可以给人一种错觉,认为多个进程同时在做事情,但实际上,所有事情都发生在一个线程中。

只需要让你的函数做一点工作,然后调用类似这样的东西:

setTimeout(function () {
... do the rest of the work...
}, 0);

任何其他需要做的事情(如UI更新,动画图像等)都会在他们有机会的时候发生。

传统上,JS是为简短、快速运行的代码而设计的。如果你有主要的计算在进行,你在服务器上做——JS+HTML 应用程序在你的浏览器中长时间运行做非琐碎的事情的想法是荒谬的。

当然,现在我们有了。但是,浏览器需要一点时间才能赶上——大多数浏览器都是围绕单线程模型设计的,要改变这一点并不容易。谷歌Gears通过要求后台执行是隔离的绕过了许多潜在的问题——不改变DOM(因为那不是线程安全的),不访问主线程创建的对象(同上)。虽然有限制,但在不久的将来,这可能是最实用的设计,因为它简化了浏览器的设计,也因为它降低了让没有经验的JS程序员在线程上瞎折腾的风险……

@marcio:

为什么不使用Javascript实现多线程呢?程序员可以用他们拥有的工具做任何他们想做的事情。

所以,让我们不要给他们的工具是如此容易滥用,每一个其他网站我打开最终崩溃我的浏览器。这种简单的实现将直接把您带入在IE7开发过程中给MS带来如此多头痛的领域:附加组件的作者在线程模型上玩得太快,导致隐藏的bug,当对象生命周期在主线程上发生变化时,这些bug就变得明显了。坏的。如果你正在为IE编写多线程ActiveX插件,我猜它是随领土而来的;不意味着还需要更进一步。

正如matt b所说,这个问题不是很清楚。假设您正在询问语言中的多线程支持:因为目前在浏览器中运行的99.999%的应用程序都不需要多线程。如果你真的需要它,有一些变通方法(比如使用window.setTimeout)。

一般来说,多线程是非常,非常,非常,非常,非常,非常,很难(我说过它很难吗?),除非你加入额外的限制(比如只使用不可变数据)。

JavaScript不支持多线程,因为浏览器中的JavaScript解释器是一个单线程(AFAIK)。即使谷歌Chrome也不会让单个网页的JavaScript同时运行,因为这会导致现有网页的大量并发问题。Chrome所做的只是将多个组件(不同的选项卡、插件等)分离到单独的进程中,但我无法想象一个页面有多个JavaScript线程。

然而,你可以使用setTimeout来允许某种调度和“伪”并发。这将导致浏览器重新获得呈现线程的控制权,并在给定的毫秒数后启动提供给setTimeout的JavaScript代码。如果您希望在对viewport执行操作时允许刷新viewport(您所看到的内容),这是非常有用的。只是循环,例如,坐标和更新相应的元素只会让你看到开始和结束的位置,而不是中间的位置。

我们在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/ < / p >

如果没有适当的语言支持线程同步,那么新的实现尝试线程同步就没有意义了。现有的复杂JS应用程序(例如任何使用ExtJS的应用程序)很可能会意外崩溃,但如果没有synchronized关键字或类似的东西,也很难甚至不可能编写正确运行的新程序。

JavaScript多线程(有一些限制)在这里。谷歌实现了Gears的worker, HTML5也包含了worker。大多数浏览器已经添加了对该特性的支持。

数据的线程安全得到了保证,因为所有与worker通信的数据都被序列化/复制。

欲了解更多信息,请阅读:

http://www.whatwg.org/specs/web-workers/current-work/

http://ejohn.org/blog/web-workers/

英特尔一直在做一些Javascript多线程的开源研究,最近在GDC 2012上展示了它。 下面是视频的链接。研究小组使用的OpenCL主要集中在英特尔芯片组和Windows操作系统。该项目代号为RiverTrail,代码可在GitHub

上获得

一些更有用的链接:

为Web应用程序构建计算高速公路

目前一些浏览器确实支持多线程。如果你需要,你可以使用特定的库。例如,查看下面的材料:

javascript多线程显然是可能的使用HTML5带来的网络工作者。

webworker和标准多线程环境之间的主要区别是内存资源不与主线程共享,对象的引用从一个线程到另一个线程是不可见的。线程通过交换消息进行通信,因此可以实现遵循事件驱动设计模式的同步和并发方法调用算法。

有许多框架允许在线程之间结构化编程,其中包括OODK-JS,这是一个支持并发编程的OOP js框架 https://github.com/GOMServices/oodk-js-oop-for-js < / p >

然而,你可以使用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;
}
}

Node.js 10.5+支持工作线程作为实验特性(你可以在启用——experimental-worker标志的情况下使用它)

所以,规则是:

  • 如果需要执行I/O绑定操作,则使用内部机制(即callback/promise/async-await)
  • 如果你需要CPU限制操作,那么使用工作线程。

工作线程是长期存在的线程,这意味着生成一个后台线程,然后通过消息传递与它通信。

否则,如果你需要用一个匿名函数执行一个沉重的CPU负载,那么你可以使用https://github.com/wilk/microjob,一个围绕工作线程构建的小型库。

Javascript是一种单线程语言。这意味着它有一个调用堆栈和一个内存堆。正如预期的那样,它按顺序执行代码,并且必须在执行下一段代码之前完成。它是同步的,但有时是有害的。例如,如果一个函数需要一段时间才能执行,或者必须等待某项操作,那么它会同时冻结所有内容。

实际上多线程与语言本身没有关系。 这是一个。net的多线程Javascript引擎。 它在多线程场景下工作得非常好。 它集成了c#运行时,所以所有的同步逻辑都类似于c#。可以启动/等待/等待任务,也可以启动线程。你甚至可以放锁。下面的示例演示了在. net运行时使用Javascript语法的并行循环

https://github.com/koculu/topaz

var engine = new TopazEngine();
engine.AddType(typeof(Console), "Console");
topazEngine.AddType(typeof(Parallel), "Parallel");
engine.ExecuteScript(@"
var sharedVariable = 0
function f1(i) {
sharedVariable = i
}
Parallel.For(0, 100000 , f1)
Console.WriteLine(`Final value: {sharedVariable}`);
");

除此之外,微软正在开发Napa.js,一个支持多线程的Node.js克隆。

https://github.com/microsoft/napajs