【问题标题】:why Javascript SetTimeout() is not multithreaded为什么 Javascript SetTimeout() 不是多线程的
【发布时间】:2012-08-29 22:30:13
【问题描述】:

我有一个测试:

HTML:

<div id="f1">Empty</div>
<div id="f2">Empty</div>

​

js:

var s1 = function() {
    for (i = 1; i < 1000000000; i++) {
        var b = i * i;
    }
    $('#f1').html('Set');
}

var s2 = function() {
    if ($('#f1').html() == 'Empty') {
        $('#f2').html('Multi Thread');
        return;            
    };
    $('#f2').html('One Thread');
}

setTimeout(s2,110);
setTimeout(s1,100);​

setTimeOut() 不是在不同的线程中运行,而是像事件模型那样运行,有什么真正的原因吗?

jsfiddle

【问题讨论】:

  • 因为javascript不是多线程的?
  • @PeeHaa 但为什么不呢?它至少有异步功能...
  • 异步函数不需要线程,它们只需要能够对事件进行排队,并且有一个事件循环可以从该队列中取出并运行它们。

标签: javascript


【解决方案1】:

Javascript 本身不是多线程的,也不是非多线程的。但是,目前主流浏览器实现的Javascript的具体实现大多是单线程的。

此外,对于适当的多线程,该语言需要具有共享内存、锁、信号量和其他并发编程工具的功能,而当前定义的 JavaScript 没有这些功能(例如,无法描述如何并发JS 线程将控制谁可以更新 DOM 对象,这些对象当然是共享的,因为一个窗口中只有一个 DOM。

尝试让 JS 更加并行化 - 看看 web worker、英特尔的 River Trail、Google's HTML5 workmore

【讨论】:

  • for (i = 1; i &lt; 1000000000; i++) { 放入一个worker 并让它resultReceiver$('#f1').html('Set');
【解决方案2】:

许多设计决策都涉及到 Javascript 在浏览器中的实现,假设它只有单线程访问浏览器 DOM 和其他全局变量/属性。这使得使用它进行编程不太可能导致问题,但引入了一些必须处理的限制。

语言本身完全具备多线程能力,我们已经在 WebWorkers 和该语言的一些服务器实现中看到了这一点。但是,任何时候您使用多个线程并尝试读取/写入在多个线程之间共享的变量或属性时,必须使用保护设备(如互斥锁)来允许对这些共享资源进行可靠访问。这使得如何进行这种编程变得非常复杂,并且浏览器中的 Javascript 决定不需要这种程度的理解来可靠地对其进行编程。

对于任何做过多线程编程的人来说,它可以很强大,但是很容易引入难以发现的错误。那些负责浏览器中 Javascript 的人决定应该完全避免这种难度级别和由此产生的错误类型。

即使现在使用 WebWorkers,WebWorker 和主 javascript 线程之间也没有共享资源。两者必须通过消息传递系统进行通信,这是一种强制安全的万无一失的方式。而且,结果是无法从 WebWorker 访问 DOM。相反,如果您希望更改 DOM,则必须向单个主线程发布消息并要求 IT 更新 DOM。主线程只有在完成其他操作时才会收到该消息(它是单线程的)。

DOM 也很可能已经花费了数亿年的时间作为一个仅为单线程访问而设计的结构,因此设计和实现一种从多线程访问它的方法将是一项艰巨的任务(并修复所有该实现中产生的错误)。

【讨论】:

    【解决方案3】:

    eicto,setTimeout 不会在请求时触发代码
    它将代码与之前的所有其他代码一起排队,内联,但它将其排队位置设置为至少请求的时间。

    此外,大多数浏览器对最小超时都有硬性限制。
    如果您请求 1 毫秒的超时,那么在大多数浏览器中,您很可能会在 10 毫秒到 15 毫秒后收到您的请求。

    所有 JS 与 DOM 的交互,实际上,几乎单个页面所做的所有事情,都发生在一个线程上,自定义浏览器扩展和一些新的 API(如 webworkers)除外。

    这就是为什么大型项目需要考虑页面上的所有其他内容,以及为什么所有内容都需要异步。

    因为setTimeout 不是sleep,它不会在cron 输入的精确微秒内返回... ...它在事件堆栈上放置一个回调,时间不早于您指定的时间。

    【讨论】:

    • 即使在 Windows API 中也不能设置 1 毫秒的时间。 C++ Sleep(1) 将休眠 15 到 30 毫秒。这同样适用于 WaitForSingleObject()。这是因为 Windows 的内部设计不是实时操作系统。
    【解决方案4】:

    Javascript 不支持多线程,因为您在浏览器中的解释器是单线程

    【讨论】:

    • 好的,但为什么不至少中断 prev 函数以及时运行代码?
    • 一个非常聪明的答案!它不是多线程的,因为它是单线程的!
    • 每个基于 UI 的程序都从单个线程(也就是 UI 线程)开始,然后创建更多线程。这不是关于“浏览器中的解释器是一个线程”
    【解决方案5】:

    JavaScript 不是多线程的,但即使是 setTimeout 也是同步的。 setTimeout 和 setInterval 由正确的 JavaScript 语言之外的浏览器提供,它提供了访问该语言的外部方法,例如事件执行。当人们将 JavaScript 称为异步或多线程语言时,这很可能是他们所指的,因为多个外部访问点(例如大量计时器或事件执行)可以同时发生,每个访问点都会在内存中生成一个对解释器的唯一访问点。这正是 Node.js 的开发人员在对 JavaScript 提出此类声明时所指的内容。

    这种对各种隔离线程的多次外部访问可能会导致 UI 中的冲突,因为模拟的多线程效果可能会导致浏览器输出中的冲突,其中只有一个文档对象代表整个页面。这就是为什么 setInterval 的间隔很短通常被认为是不安全的。 setInterval 是完全异步的,即使在前一个时间间隔内的执行还没有结束,它也会按照提供的时间间隔执行。这种碰撞就是我所说的故障转移,因为下一个时间间隔是执行的代码会超过之前的执行,如果您的代码需要访问 DOM 或使用闭包,您可能会遇到问题。为安全起见,建议使用递归 setTimeout,因为它是同步的,并且在前一轮完成之前不会发生下一轮执行。

    【讨论】:

    • 这里我们看一个例子,当 SetTimeout 是同步的,其他的超时等待第一个执行一个
    【解决方案6】:

    Javascript 不是多线程的。

    HTML5 将赋予 javascript 多线程功能。

    【讨论】:

      【解决方案7】:

      Mozilla 确实支持 Javascript 中的多线程 - 只要您不想从多个线程执行 UI 工作。我的Remove Duplicate Messages (Alternatve) exentsion 的早期版本是多线程的。

      请参阅 my own bug page 关于我的扩展程序中的这个问题,或者更好的是 this page 关于在 Mozilla 中使用工作线程的信息。 eicto,您可以使用后台线程很好地实现您的代码。

      【讨论】:

        【解决方案8】:

        等待给定的时间后,方法(s1,s2)的执行仍然发生在javascript线程本身(单线程)中。

        s2等待s1的原因

        【讨论】:

        • 为什么投反对票?请解释一下,帮助我了解是否有问题;)
        猜你喜欢
        • 2010-09-07
        • 2013-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-29
        • 1970-01-01
        • 2014-12-06
        相关资源
        最近更新 更多