【问题标题】:Can we have race conditions in single-threaded scripting languages? [duplicate]我们可以在单线程脚本语言中有竞争条件吗? [复制]
【发布时间】:2015-04-25 15:50:06
【问题描述】:

我经常读到您不必担心 javascript 中的竞争条件,因为它是单线程的。但我相信这是因为Run-to-completion 事件循环的性质。如果 Javascrit 没有“Run-to-completion”功能,它仍然可能存在并发问题。

让我们考虑一下这段代码sn-p:

1  var pending = [];

2  document.getElementById("submitBtn").addEventListener(function() {
3      var val = document.getElementById("textBox").value;
4      pending.push(val);
5  });

6  setInterval(function() {
7     processValues(pending);
8     pending = [];
9  }, 3000);

假设 javascript "Run-to-completion" 中没有这样的功能,并且任何事件都可以被抢先运行另一个事件/代码。

现在假设第 7 行被执行,突然事件被抢占处理第 3 行的事件。执行第 3 行和第 4 行后,前一个事件从第 8 行恢复。现在当第 8 行执行时,新的pending 中的附加值将丢失,因为它既不被 processValues 函数处理,也不在 pending 数组中。

即使是单线程的,也会发生竞争条件。那么,说 javascript 是单线程的就没有竞态条件是不对的?具体来说,是因为Run-to-completion javascript 的特性?

编辑

显然,javascript 中可能存在竞争条件。我指的是由于javascript的单线程(或Run-to-completion?)性质而不会发生的某些竞争条件。比如我上面介绍的那个。

【问题讨论】:

  • 你在哪里读到的?竞争条件在异步代码中很常见。
  • 在 javascript、websockets 等的异步部分中可能存在竞争条件。
  • 如果你好奇的话,已经为此提供了一个深思熟虑的答案:stackoverflow.com/questions/21463377/…
  • @Jivings @adeno 查看问题的答案stackoverflow.com/questions/21467325/…
  • @brianvaughn 答案指出“竞争条件只能发生在两个或多个线程之间”,我认为这在脚本语言的情况下是不正确的。这让我很困惑。

标签: javascript multithreading concurrency race-condition


【解决方案1】:

是的,我们在单线程 JavaScript 中有竞争条件。只是没有多线程代码那么多(前提是你不使用alertconfirm,更多内容见下文)。

您首先说“假设没有运行到完成功能”,然后描述了依赖于此的竞争条件。但是这种竞争条件不会发生,因为正如你所说,JavaScript 已经运行到完成。

虽然在 JavaScript 中确实有一类竞争条件是我们不必担心的,但仍有很多我们确实需要担心。例如,异步代码总是有可能出现竞争条件。 (这就是 ajax 调用、来自网络工作者的消息等)

以下是您经常看到的错误示例,这是现实世界的竞争条件:

var img = document.createElement('img');
img.src = "kittens.png";
img.onload = function() {
    console.log("It loaded");
};
document.body.appendChild(img);

这很安全,对吧? 错误。 JavaScript 是单线程运行的,并不意味着浏览器是单线程的。当浏览器看到img.src = "kittens.png"; 时,如果图像在缓存中,则完全有权在该load 上触发load 事件:该事件将查找任何处理程序,找不到任何处理程序,因此不会排队当前代码完成后要运行的任何回调 - 我们看不到“它已加载”消息。

虽然这是一个基于浏览器的示例,但它是一个一般原则的示例:仅仅因为主机环境运行单个主 JavaScript 线程,这并不意味着 主机环境 不是' t 多线程,并且多线程可能会对我们的单线程代码产生影响。

这只是一个例子。但这是真的,我们对其他一些人是安全的。例如,如果我们更改上面的代码:

var img = document.createElement('img');
img.onload = function() {
    console.log("It loaded");
};
img.src = "kittens.png";
document.body.appendChild(img);
doSomethingElse();

...我们知道 doSomethingElse 将在"It loaded" 运行之前被调用,除非在alert 周围的某些浏览器(我正在看着你,Mozilla)上出现一些不愉快的边缘情况和confirm 函数; bobince covers those in this other answer。 (TL;DR - 至少某些版本的 Firefox 会在等待用户关闭 alert 时触发 ajax 完成回调。)

【讨论】:

  • 不错的答案。虽然我认为问题在于 javascript 并不是真正的单线程。如果你看一个简单的 Java 程序,没有启动任何线程或任何东西,也没有异步方法(我认为实际上异步意味着多线程),那么就不可能创建竞争条件,对吧?
  • @maraca:嗯,JavaScript,这种语言,对线程完全保持沉默。唯一的线程保证由主机提供。 网络浏览器上的 JavaScript 可以访问单个 UI 线程和 X 数量的网络工作者。忽略网络工作者,基于浏览器的 JavaScript 确实是单线程的,除非我在答案末尾提到的问题,而且网络工作者被非常智能地设计为使用消息事件模型和工作者隔离来避免破坏它。同样地,NodeJS 上的 JavaScript 也被 NodeJS 保证为单线程。 JVM 上的 JavaScript(Rhino、Nashorn)不是。
  • @T.JCrowder 是的,这正是我的观点,你不能将它应用于 JavaScript,但它可能适用于其他语言。
  • @T.J.Crowder 没错,javascript 中可能会出现竞争条件。请参阅我更新的问题。
猜你喜欢
  • 1970-01-01
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-12
相关资源
最近更新 更多