为什么JavaScript不支持多线程?


269

是当今的浏览器是否经过深思熟虑的设计决策或存在问题,这些问题将在以后的版本中得到解决?


3
另请参阅JavaScript和线程问题的答案以获取有关Web Worker / Worker线程的信息。
山姆·哈斯勒

115
您好,Googler同伴。您可能会注意到,这里的所有内容似乎都是过时的(请注意,这个问题是5年前问的。)自从被问到以来,据我所知,Web浏览器已经获得了一些或多或少的多线程功能。看一下Web Workers:msdn.microsoft.com/en-us/hh549259.aspx
ArtOfWarfare 2013年

2
Multithread.js包装了Web Workers,并允许在JS中轻松进行多线程处理。适用于所有新浏览器,包括iOS Safari。:)
kwh

Answers:


194

JavaScript不支持多线程,因为浏览器中的JavaScript解释器是单线程(AFAIK)。甚至谷歌浏览器也不允许单个网页的JavaScript同时运行,因为这会在现有网页中引起大量的并发问题。Chrome所做的全部工作就是将多个组件(不同的选项卡,插件等)分离到单独的进程中,但是我无法想象一个页面具有多个JavaScript线程。

但是,您可以按照建议使用setTimeout来进行某种调度和“伪”并发。这将导致浏览器重新获得对呈现线程的控制,并setTimeout在给定的毫秒数后启动提供的JavaScript代码。如果要在对视口执行操作时允许其刷新(视口),这将非常有用。仅仅循环遍历例如坐标并相应地更新元素就可以让您看到开始位置和结束位置,而中间没有任何内容。

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


73
我认为从未实施过的视野太窄。我保证Web应用程序最终将能够实现真正的多线程(这是合乎逻辑的,因为Web应用程序变得越来越占主导地位,硬件变得更加并行),而且正如我所看到的那样,因为JavaScript是Web开发的实际语言,最终将不得不支持多线程或被其他替代。
devios1 2011年

6
从来都不是一个过于大胆的声明:),但我仍然认为,在可预见的将来,真正的多线程javascript的优势并不可行;)
Kamiel Wanrooij 2011年

5
尽管我认为Web工作者通过流程模型比线程模型更具并发性。Web工作者使用消息传递作为通信手段,这是对多线程应用程序中“常见”并发问题的一种优雅解决方案。我不确定它们是否真的可以同时操作与主页相同的对象。据我所知,他们无法访问DOM。不过,其中大多数是语义,Web Worker出于所有意图和目的看起来都很有前途。
Kamiel Wanrooij 2012年

困难比其他可能性还要大,我不确定您是否想到了所有其他可能性。我特别考虑在游戏或图形可视化中使用webgl的情况。例如,考虑使用新的3D版本的Google地图。在拥有许多3D模型的城市中,当必须渲染许多房屋时,我的PC需要大约2分钟的时间来加载所有内容。从某些角度来看,我的图形卡和网络都无法正常工作。但是8个处理器中有1个是100%。如以下示例所示,就fps而言,多线程也是一个大问题:youtube.com/watch?
v=sJ2p982cZFc

25

JavaScript多线程(有一些限制)在这里。Google实施了Gears的worker,并且HTML5中包含了worker。大多数浏览器已经添加了对此功能的支持。

保证数据的线程安全性,因为与工作人员通信的所有数据均已序列化/复制。

有关更多信息,请阅读:

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

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


8
但是,它不是更多的多进程方法,而是多线程的吗?已知线程可以在单个堆中工作。
Beefather

1
@beefeather,是的。它更多是一种过程方法。
尼尔

23

传统上,JS旨在用于简短,快速运行的代码段。如果您要进行大量计算,那么您是在服务器上完成的-一个JS + HTML 应用程序可以长时间运行在浏览器中做不重要的事情的想法是荒谬的。

当然,现在我们有了。但是,浏览器要赶上一点时间-大多数浏览器都是围绕单线程模型设计的,要更改它并不容易。Google Gears通过要求隔离后台执行来避免很多潜在的问题-请勿更改DOM(因为它不是线程安全的),也不能访问由主线程创建的对象(同上)。尽管有一定的局限性,但这可能是近期内最实用的设计,这既是因为它简化了浏览器的设计,又因为它降低了让经验不足的JS编码器弄乱线程所涉及的风险...

@marcio

为什么不使用Java脚本实现多线程的原因呢?程序员可以使用自己拥有的工具做任何想做的事情。

因此,我们不要为他们提供易于滥用的工具,以至于我打开的每个其他网站都最终导致浏览器崩溃。天真的实现会使您直接进入导致IE7开发过程中MS头疼的领域:附加作者在线程模型中玩得很快而又松懈,导致隐藏的错误在对象生命周期在主线程上更改时变得很明显。坏。如果您正在为IE编写多线程ActiveX加载项,我想它就是其中的一部分。并不意味着它需要进一步发展。


6
“它降低了>允许缺乏经验的JS代码>弄乱线程所涉及的风险”为什么这是不使用Java脚本实现多线程的原因?程序员可以使用自己拥有的工具做任何想做的事情。无论是好是坏,这都是他们的问题。使用Google Chrome流程模型,它甚至不会影响其他应用程序。:)
Marcio Aguiar '09

3
@ Shog9-“让我们不要给那些容易被滥用的[程序员]工具,以至于我打开的每个其他网站都最终导致浏览器崩溃。” - 什么?按照同样的逻辑,任何语言都不应具有多线程,因为如果它们提供了您尝试打开的所有其他程序都将崩溃。除非它不能那样工作。线程在大多数语言中都存在,并且大多数新手程序员都不会使用它,大多数不将其投入生产的应用以及从未流行或广泛使用的应用程序。
ArtOfWarfare 2013年

11

我不知道此决定的理由,但我知道您可以使用setTimeout模拟多线程编程的一些好处。尽管实际上所有事情都在一个线程中发生,但是您可以给出多个进程同时执行的幻觉。

只是让您的函数做一些工作,然后调用类似的代码:

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

只要有机会,其他需要做的事情(例如UI更新,动画图像等)就会发生。


大多数情况下,我想在loop内部使用,setTimeout但显然不起作用。你有没有做过这样的事情,或者你有黑客?一个示例是1000个元素的数组,我希望在两个setTimeout调用中使用两个for循环,这样第一个循环通过and print元素0..499,第二个循环通过and print元素500..999
benjaminz

通常,该技术是保存状态并继续。例如,假设您要打印0到1000,可以打印0到499,然后使用参数500进行setTimeout技巧。内部代码将知道采用参数(500)并从此处开始循环。
2017年

8

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

第一个问题的答案是,浏览器中的JavaScript应该在沙箱中以与机器/操作系统无关的方式运行,添加多线程支持将使该语言变得复杂,并使该语言与操作系统之间的联系过于紧密。


6

Node.js 10.5+支持将工作线程作为实验功能(您可以在启用--experimental-worker标志的情况下使用它):https : //nodejs.org/api/worker_threads.html

因此,规则是:

  • 如果您需要执行I / O绑定操作,则可以使用内部机制(又名callback / promise / async-await)
  • 如果需要执行CPU绑定的ops,请使用辅助线程。

工作线程旨在用作长寿线程,这意味着您会生成一个后台线程,然后通过消息传递与其进行通信。

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


4

正如马特b所说,这个问题不是很清楚。假设您正在询问有关该语言的多线程支持:因为当前在浏览器中运行的99.999%的应用程序不需要多线程支持。如果您确实需要它,可以使用一些解决方法(例如使用window.setTimeout)。

通常,除非您施加了额外的限制(例如仅使用不可变数据),否则多线程很难,非常非常,非常非常非常(我说这很难吗?)来做到正确。




1

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

Google应该在今天发布的新浏览器(Google Chrome)通过将进程分开来并行执行一些代码。

当然,核心语言可以提供与Java相同的支持,但是对诸如Erlang并发之类的支持还远远没有到来。


1

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


0

据我所知,谷歌浏览器将具有多线程javascript,因此这是一个“当前实现”问题。


0

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


-1

但是,您可以使用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;
    }
}

-2

使用HTML5带来的网络工作者显然可以使用javascript实现多线程。

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

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


5
共享内存是与单独进程(例如fork()vs exec())相对的Thread的确切定义。线程可以共享对象,进程必须使用IPC。Web Worker不是多线程的。
felixfbecker 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.