繁体   English   中英

Node.js 中 JavaScript/TypeScript 中的异步/等待控制流

[英]Async/Await control flow in JavaScript/TypeScript in Node.js

上下文:我正在尝试在 TypeScript 中实现一个基本的套接字池。 我当前的实现只是一个 sockets 列表,它们附加了一个“可用/占用”枚举(诚然,它可能是一个 boolean),它允许我有一个类似互斥锁的机制来确保每个套接字只发送/接收单个消息立刻。

我的理解:我知道 Node.js 处理“并行”操作的方式是“单线程异步”。

我推断:对我来说,这意味着一次只有一个“控制指针”/“代码读取头”/“控制流位置”,因为只有一个线程。 在我看来,只有在调用“等待”时,读数头才会跳转到代码中的其他位置,而我正在“等待”的 Promise 尚无法解决。 但我不确定情况是否确实如此。

我想知道的是:“单线程异步”是否确保在调用“await”之外的任何其他时间确实没有控制流 position 的跳转? 或者是否有一些底层调度程序可能确实会在随机时刻导致任务之间的跳转,比如正常的多线程?

我的问题:所有这一切要问,我是否需要一个纯互斥/比较和交换机制来确保我的类似互斥的 AVAILABLE/OCCUPIED 字段设置正确?

考虑以下代码:

export enum TaskSocketStatus
{
    AVAILABLE,  //Alive and available
    OCCUPIED,   //Alive and running a task
}

export interface TaskSocket
{
    status:TaskSocketStatus;
    socket:CustomSocket;
}


export class Server //A gateway that acts like a client manager for an app needing to connect to another secure server
{
    private sockets:TaskSocket[];

    [...]

    private async Borrow_Socket():Promise<TaskSocket|null>
    {
        for (const socket of this.sockets)
        {
            if (!socket.socket.Is_Connected())
            {
                await this.Socket_Close(socket);
                continue;
            }
            if (socket.status === TaskSocketStatus.AVAILABLE)
            {
//This line is where things could go wrong if the control flow jumped to another task;
//ie, where I'd need a mutex or compare-and-swap before setting the status
                socket.status = TaskSocketStatus.OCCUPIED;
                return (socket);
            }
        }
        if (this.sockets.length < this.max_sockets)
        {
            const maybe_socket = await this.Socket_Create();
            if (maybe_socket.isError())
            {
                return null;
            }
 //Probably here as well
            maybe_socket.value.status = TaskSocketStatus.OCCUPIED;
            return maybe_socket.value;
        }
        return null;
    }

    [...]
 }

我希望避免的问题是两个不同的“SendMessage”任务由于竞争条件而借用了同一个套接字。 也许这是不必要的担心,但我想确定一下,因为这是一个潜在的问题,我真的不想在服务器已经投入生产时不必面对......

谢谢你的帮助 !

因此,另一个操作的控制流不是在调用await时进行的。 当 Javascript 的运行部分返回事件循环时,事件循环可以为下一个等待事件提供服务。 已解决的承诺也通过事件循环工作(一个特殊的队列,但仍在事件循环中)。

因此,当您点击await时,不会立即将控制权转移到其他地方。 It suspends further execution of that function and then causes the function to immediately return a promise and control continues with a promise being returned to the caller of the function. 调用者的代码在收到那个 promise 后继续执行。 只有当调用者或调用者的调用者或调用者的调用者的调用者(取决于调用堆栈的深度)从任何事件开始时返回到事件循环,这整个执行链才会事件循环得到一个有机会为下一个事件服务并开始新的执行链。

一段时间后,当连接到原始await的底层异步操作完成时,它将向事件队列中插入一个事件。 当其他 Javascript 执行将控制权返回给事件循环并且此事件到达事件队列的开头时,它将被执行并解析await正在等待的 promise。 只有这样, await之后 function 中的代码才有机会运行。 When that async function that contained the await finally finishes it's internal execution, then the promise that was originally returned from the async function when that first await was hit will resolve and the caller will be notified that the promise it got back has been resolved (assuming它在该承诺上使用了await.then() )。

因此,没有从一个地方到另一个地方的流量跳跃。 Javascript 执行的当前线程将控制权返回给事件循环(通过返回和展开其调用堆栈),然后事件循环可以为下一个等待事件提供服务并开始新的执行链。 只有当该执行链完成并返回时,事件循环 go 才能获取下一个事件并开始另一个执行链。 这样,一次只有一个调用堆栈帧。

在您的代码中,我不太了解您所关心的内容。 Javascript 中没有抢先切换。 如果您的 function 执行await ,则其执行将在此时暂停,其他代码可以在 promise 得到解决之前运行,并在await之后继续执行。 但是,没有先发制人的切换可以更改上下文并在此线程中运行其他代码,而无需您的代码调用一些异步操作,然后在完整的回调中或在await之后继续。

因此,从纯 Javascript 的角度来看,不涉及异步操作的纯本地 Javascript 语句之间没有任何顾虑。 这些保证是连续的和不间断的(我们假设没有涉及使用共享 memory 和工作线程的代码 - 在您发布的代码中没有任何迹象)。

我想知道的是:“单线程异步”是否确保在调用“await”之外的任何其他时间确实没有控制流 position 的跳转?

它确保在任何时候都没有控制流 position 的跳转,除非您返回事件循环(展开调用堆栈)。 它不会发生在await await可能会导致您的 function 返回,并可能导致调用者在等待返回的 promise 解决时返回事件循环,但重要的是要了解控制流更改仅在堆栈展开并返回控制权时发生到事件循环,以便可以从事件队列中拉出下一个事件并进行处理。

或者是否有一些底层调度程序可能确实会在随机时刻导致任务之间的跳转,比如正常的多线程?

假设我们不是在谈论 Worker Threads,那么 nodejs 中没有抢先式 Javascript 线程切换。 仅当 Javascript 的当前线程返回到事件循环时,对另一块 Javascript 的执行才会更改。

我的问题:所有这一切要问,我是否需要一个纯互斥/比较和交换机制来确保我的类似互斥的 AVAILABLE/OCCUPIED 字段设置正确?

不,您不需要互斥锁。 在测试和设置之间没有返回事件循环,因此保证它们不会被任何其他代码中断。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM