【问题标题】:How an async call stack is implemented如何实现异步调用堆栈
【发布时间】:2019-08-03 06:17:47
【问题描述】:

假设你有这个函数序列(JavaScript)......

A(function(){
  console.log('done')
})

function A(done) {
  a()
  B(D, done)
}

function B(x, y) {
  x(function(){
    c()
    C(y)
    d()
  })
}

function C(z) {
  g()
  setTimeout(z, 1000)
}

function D(z) {
  h()
  setTimeout(z, 2000)
}

function a() {
  b()
  c()
}

function b() {
  // ... sync stuff
}

function c() {
  e()
  // ... sync stuff
  f()
}

function d() {
  // ... sync stuff
}

试着让它有一种复杂的调用堆栈。

我想知道的是调用堆栈在不同时间点的样子。例如,c();C(y);d() 序列。当c() 被调用时,在该级别调用的下一个 函数是C()。所以它似乎会推入堆栈(在评估c() 之前),C() 是返回位置。然后它转到e()f()(暂时忽略它)。然后它检查调用堆栈并返回到C()。然后同样的过程。但由于C() 是异步的,它会在C() 完成之前转到d()。所以是这样的:

c   c   c   c   c   c     c    ...?
    C   C   C   C   C    /  \
        e   e   f       C    d
            f

这就是我在尝试绘制调用堆栈时的想法。它似乎会形成一棵树。现在想象一下多个异步进程几乎同时开始。然后它就像一棵树的多个分支。所以不是调用堆栈,而是调用树。这让我最终质疑调用堆栈是如何被评估的。 序列中的下一个函数被推入调用堆栈时,以及它们如何更新/删除最后完成的函数并找到返回调用中下一个位置的方法堆栈/树。

想知道您是否可以指出任何可能描述这一点的资源,或者甚至可以解释调用堆栈在我上面描述的示例中的外观。

【问题讨论】:

  • 这真的不是一个装配问题。不要将其视为单个调用堆栈。将异步执行视为线程中的多个调用堆栈。

标签: function compiler-construction callstack


【解决方案1】:

当你调用一个函数时,你将返回地址压入堆栈,而不是下一个要调用的函数。然后被调用的函数将在堆栈上创建自己的帧(您可以考虑该帧的返回地址部分或与该帧分开,这取决于您如何看待它。当函数返回时,它将弹出其帧并返回到返回地址(也将隐式或显式弹出返回地址 - 详细信息取决于 CPU/VM 架构。

因此,对于您的示例,随着时间的推移调用堆栈看起来更像

c c c c c C C
  e   f     g

【讨论】:

  • 但是返回地址好像是下一个函数,看不出有什么不同。而且也不确定异步情况下会发生什么。
  • 不,返回地址在当前函数的中间。在这种情况下,当前函数中的下一件事是另一个调用(对下一个函数),但它可以是任何东西。
猜你喜欢
  • 2016-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2010-09-22
  • 2013-03-31
  • 2021-10-11
相关资源
最近更新 更多