【问题标题】:is there a probability of thread unsafety in javascript?javascript中是否存在线程不安全的可能性?
【发布时间】:2019-03-20 03:11:31
【问题描述】:

let arr = [2, 3]

let promiseA = new Promise((resolve)=>{
    // await for io
    resolve(arr.shift())
})
let promiseB = new Promise((resolve)=>{
    // await for io
    resolve(arr.shift())
})
let handler = (data)=>{
    if(!data){
        return console.log("no more")
    }
    console.log(data)
}
promiseA.then(handler)
promiseB.then(handler)

您好,我有一个关于 javascript 并发的问题。

如果promiseApromiseB一一解决,那就没有问题了。

但是,如果两个 io 操作花费相同的时间,是否有可能将 promiseApromiseB 都解析为值 2

【问题讨论】:

  • JavaScript 不是并发语言。编程模型是单线程的。一个 Promise 会先于另一个解决,所以就是这样,但这并不是真正的 并发 问题,而是 同步 问题。最重要的是,编写这样的代码可能不是一个好主意。
  • 输出可能是3,然后是2。不可能是2,然后是2
  • 让您的问题更有趣...下次使用 Web Workers 并创建多个进程并提出相同的问题。当然,答案仍然与 Pointy 所说的相同,但会是一个更有趣的问题! :-)

标签: javascript asynchronous concurrency


【解决方案1】:

@Pointy(在 cmets 中)是正确的,但只是为了形式化它:


Promise 正文、消息和事件循环

在两个 Promises 的主体中运行的任何代码都将作为主 JavaScript Event Loop 中的消息执行。

JavaScript 一次运行一条消息,一旦一条消息在主事件循环中运行,它将在其他任何事情发生之前run to completion

...它不能被抢占,并且会在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。

setTimeout queue messages 之类的调用用于主事件循环,因此在两个Promises 的主体中完成的工作可能跨越多条消息,但每条消息一次运行一条并运行到完成之前其他任何东西都会运行。

所以在每个promise body到达这一行的时候:

resolve(arr.shift())

...它将是当前正在运行的消息并且“不能被抢占并且将在任何其他代码运行之前完全运行”。


Promise 回调和 PromiseJobs 队列

Promise 解析时,任何在Promise 上等待的回调都会在PromiseJobs queue 中排队,PromiseJobs queue 是 ES6 引入的特殊作业队列。

PromiseJobs 队列中的回调在当前消息完成之后和下一条消息开始之前运行并按顺序一次运行一个,直到队列为空。


那么...是否有可能将 promiseA 和 promiseB 都解析为值 2?

没有。 Promises 将解析为值 2 的可能性为零。

这一行:

resolve(arr.shift())

...是同步的,数组操作和resolve 将在任何其他代码运行之前作为当前正在运行的消息的一部分运行到完成。

这意味着每个handler 回调都保证在 PromiseJobs 中以唯一值排队。


奖金

代码的编写方式,handler 保证先在 PromiseJobs 中以2 排队,然后在 PromiseJobs 中以3 排队,不管哪个Promise 先解析,因此handler 回调保证按该顺序运行,并且上面的代码将总是在打印2 之前打印3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多