JavaScript 多线程

Posted

技术标签:

【中文标题】JavaScript 多线程【英文标题】:JavaScript multithreading 【发布时间】:2011-11-30 03:40:50 【问题描述】:

我正在比较几种在 javascript 中实现(真实或虚假)多线程的不同方法。据我所知,只有 webworkers 和 Google Gears WorkerPool 可以为您提供真正的线程(即分布在具有真正并行执行的多个处理器上)。我找到了以下方法:

使用yield()在任务之间切换

setInterval()(或其他非阻塞函数)用于等待另一个线程的线程

使用 Google Gears WorkerPool 线程(带有插件)

使用 html5 网络工作者

我阅读了相关问题,发现了上述方法的几种变体,但大多数问题都是旧的,所以可能会有一些新想法。

我想知道 - 你还能如何在 JavaScript 中实现多线程?还有什么重要的方法吗?

更新: 正如 cmets 中所指出的,我真正的意思是并发。

更新 2:我发现 Silverlight + JScript 支持多线程的信息,但我无法验证这一点。

更新 3: Google 已弃用 Gears:http://code.google.com/apis/gears/api_workerpool.html

【问题讨论】:

我认为你的问题是如何在 Javascript 中实现并发。正如您所说,调用 yield() 或使用 setInterval() 不算数。此外,网络工作者与本地操作系统线程并不完全一样,因为代码必须隔离在单独的文件中,并且只能使用事件进行通信。同样,工作人员可能会或可能不会在后台使用真正的操作系统线程——尽管它们允许您在不加思索的情况下实现类似的并发性。 没错。不使用正确的词汇是我的坏事。 除了插件,我认为你的列表很不错。我认为 web-workers 确实是最好的(最兼容的)方法,虽然不能保证他们使用多个 CPU 内核,但这取决于 JavaScript 引擎。 【参考方案1】:

Web Workers。它们是 W3C 标准(嗯,目前是工作草案),并且不需要插件:

该规范定义了一个 API,允许 Web 应用程序作者生成后台工作人员,在其主页上并行运行脚本。

该规范还讨论了将工作线程分散到多个内核,以实现真正的并发(这由浏览器的 JavaScript 引擎无形地处理):

随着多核 CPU 的普及,获得更好性能的一种方法是将计算成本高昂的任务分配给多个工作人员。在 [one] 示例中,将针对从 1 到 10,000,000 的每个数字执行的计算成本高昂的任务被外包给 10 个 subworker。

yield()setInterval() 只安排稍后发生的事情,它们不会与其他任何事情同时运行。

【讨论】:

但是 +1 链接,在 JS 中寻找并发的人可能会发现它很有用 @KrzysztofHasiński 我认为 Web Workers 是目前在浏览器中的 JavaScript 中拥有多个线程的最佳/唯一方法。 我同意,这是最好的方法,但我真的不想选择最好的,我只是想收集不同的方法并比较实现(在 Chrome 和 Fx 中)和性能简短的讲座。 在很长一段时间后没有什么新东西了,我想指出人们正在寻找一种在 JS 中进行并发的方法的正确方向,所以我接受这个答案:) 要真正使用 Web Workers 的强大功能,您必须使用“可传输对象”,它允许在主线程和工作线程之间移动大块数据而无需复制。传递对象“结构化复制”通常会破坏使用工作者的性能优势。【参考方案2】:

我想知道 - 你还能如何在 JavaScript 中实现多线程?还有什么重要的方法吗?

您可以将您的代码转换为没有任何显式循环或直接函数调用的 JavaScript 代码,而是将代码分成由线程引擎管理的小执行单元。在我的示例代码中,我展示了如何转换带有循环的函数,但我省略了函数调用的机制,只是为了保持示例简单。

转换过程基本上是通过在分割点拆分代码来实现的。这些划分点是函数调用和循环(如上所示)。在示例中,我使用了对象和键,但如果 unitsstack 存储为对象变量(即使用 @ 存储987654321@ 而不是 stack["foo"] = bar)。

例如下面的代码:

// Phoney method purely to demonstrate structure
function Foo() 
  var i,
      sum = 0,
      accumulator_list = [],
      accumulator_modulus = [],
      kMaxAccumulatorCount = 100;

  // Calculate accumulations
  for(i = 0; i < kMaxAccumulatorCount; ++i) 
    current_accumulator = GetNextAccumulator()
    accumulator_list[i] = current_accumulator;
    sum = sum + current_accumulator;
  

  // Calculate accumulator modulus
  for(i = 0; i < kMaxAccumulatorCount; ++i) 
    current_accumulator = accumulator_list[i];
    accumulator_modulus[i] = current_accumulator % kMaxAccumulatorCount;
  

...变成这样的:

function Foo_A(caller,stack) 
  var stack = ;
  stack["i"] = undefined;
  stack["sum"] = 0;
  stack["accumulator_list"] = [];
  stack["accumulator_modulus"] = [];
  stack["kMaxAccumulatorCount"] = 100;

  stack["i"] = 0;
  return caller: caller, stack: stack, next=Foo_B;


function Foo_B(caller, stack) 
  stack["current_accumulator"] = GetNextAccumulator();
  stack["accumulator_list"][stack["i"]] = stack["current_accumulator"];
  stack["sum"] = stack["sum"] + stack["current_accumulator"];

  // For-loop condition satisfied ?
  if(stack["i"] < stack["kMaxAccumulatorCount"]) 
    ++stack["i"];
    return caller: caller, stack: stack, next:Foo_B;
   else 
    // Initialise the next for loop.
    stack["i"] = 0;
    return caller: caller, stack: stack, next:Foo_C;
  


function Foo_C(caller, stack) 
  stack["current_accumulator"] = stack["current_accumulator"][stack["i"]];
  stack["accumulator_modulus"][stack["i"]] = stack["current_accumulator"] % stack["kMaxAccumulatorCount"];

  // For-loop condition satisfied ?
  if(stack["i"] < stack["kMaxAccumulatorCount"]) 
    ++stack["i"];
    return caller: caller, stack: stack, next:Foo_C;
   else 
    // Function has finished so the next will be null. When the thread-engine sees this it simulates the behaviour of a return, pops its virtual stack and returns execution to the caller
    return caller: caller, stack: stack, next:null;
  

【讨论】:

【参考方案3】:

Multithread.js 是一个非常简单的 JS 多线程库,它封装了 Web Workers 并为您完成大部分工作。 :)

【讨论】:

不错的补充,虽然这些仍然是 Web Workers :)【参考方案4】:

在 JavaScript 中没有直接支持多线程。但是,您可以通过应用一些想法和方法来实现这一点。

有如下方法:

var id = window.timeout("javascript code", time);

这里的JavaScript代码在指定时间后被调用,我们可以使用

window.clearTimeout(id);

用于清算。 这样我们就可以实现伪并发。

【讨论】:

这只是setInterval() 的一个变体。正如有问题(网络工作者)所指出的那样,有一种直接的方法可以进行多线程处理。 +1 用于提及clearTimeout(),我将它用于我的演示代码。【参考方案5】:

问:你怎么能在 Javascript 中实现并发

您可以使用异步或“非阻塞”类型的方法。这是关于 node.js 系统的主要讨论之一。 它不完全是多线程的,但它确实往往更快。

【讨论】:

除了setIntervalsetTimeout,还有哪些非阻塞方式?有什么与这两者有显着不同的吗?

以上是关于JavaScript 多线程的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 多线程

JavaScript多线程

HTML5之Javascript多线程

为啥 JavaScript 不支持多线程?

如何实现javascript多线程同时运行?

javascript中的多线程和订阅/发布方法