32

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

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

  • 使用setInterval()(或其他非阻塞函数)与线程等待另一个

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

  • 使用 html5 网络工作者

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

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

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

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

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

4

5 回答 5

25

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

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

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

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

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

于 2011-10-07T04:31:18.320 回答
4

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

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

转换过程基本上是通过在分割点拆分代码来实现的。这些划分点是函数调用和循环(如上所示)。在示例中,我使用了对象和键,但如果单元将堆栈存储为对象变量(即使用this.foo = bar而不是存储stack["foo"] = bar),则在浏览器的 JavaScript 引擎上可能会容易得多。

例如下面的代码:

// 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};
  }
}
于 2013-05-27T08:34:50.440 回答
3

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

于 2014-02-28T14:47:23.253 回答
2

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

有如下方法:

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

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

window.clearTimeout(id);

用于清算。通过这个我们可以实现假并发。

于 2011-10-06T05:54:52.877 回答
1

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

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

于 2011-10-07T00:16:47.810 回答