我们可以在单线程脚本语言中使用竞争条件吗?

时间:2015-04-25 15:50:07

标签: javascript multithreading concurrency race-condition

我经常读到你不必担心javascript中的竞争条件,因为它是单线程的。但我认为这是因为事件循环的Run-to-completion性质。如果Javascrit没有" Run-to-completion"它可能仍会出现并发问题。特征

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

pending

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

现在假设第7行被执行并且突然事件被抢先处理第3行的事件。执行第3行& 4,前一个事件从第8行恢复。现在当第8行被执行时,processValues中新添加的值将丢失,因为pending函数既没有处理它也没有#39} ; s在{{1}}数组中。

即使是单线程,也会出现竞争状况。那么,说javascript没有竞争条件是不对的,因为它是单线程的?具体来说,这是因为javascript的Run-to-completion功能?

修改

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

1 个答案:

答案 0 :(得分:2)

是的,我们在单线程JavaScript中有竞争条件。只是没有多线程代码那么多(如果您不使用VS2010alert,请参阅下文)。

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

虽然我们不需要担心JavaScript中存在一类竞争条件,但仍有很多我们需要担心的事情。例如,异步代码将始终具有竞争条件的潜力。 (这是ajax调用,来自web worker的消息等)

这是一个你常见的错误的例子,这是一个现实世界的竞争条件:

confirm

那是安全的,对吗? 错误。仅仅因为 JavaScript 运行单线程,并不意味着浏览器是单线程的。当浏览器看到var img = document.createElement('img'); img.src = "kittens.png"; img.onload = function() { console.log("It loaded"); }; document.body.appendChild(img); 时,如果图像位于缓存中,则完全有权在img.src = "kittens.png";上触发load事件:该事件将查找任何处理程序,而不是查找任何,所以在当前代码完成后不排队任何回调 - 我们没有看到“已加载”消息。

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

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

img

...我们知道 var img = document.createElement('img'); img.onload = function() { console.log("It loaded"); }; img.src = "kittens.png"; document.body.appendChild(img); doSomethingElse(); 将在doSomethingElse运行之前被调用,除非在某些浏览器上遇到一些令人不快的边缘情况(我在看着你,Mozilla) "It loaded"alert函数; bobince covers those in this other answer。 (TL; DR - 至少某些版本的Firefox会在等待用户解除confirm 时触发ajax完成回调。)