繁体   English   中英

了解.NET中的等待和异步

[英]Understanding await and async in .NET

我正在研究使用Bootstrap协议来更新机器中多个节点的固件的重构代码。 当前代码看起来像这样(伪代码):

public void StartUpdate()
{
    Sokcet bootpSocket = new Socket():
    StateObject bootpState = new StateObject(bootpSocket);

    BOOTPReceive(bootpState);
    SendMagicPacket();

    while (!IsError && !IsUpdateComplete)
    {
        //wait for BOOTP/Update to finish before returning to caller
    }
}

private void BOOTPReceive(object state)
{
    bOOTPSocket.BeginReceive(PACKET_DATA, 0, PACKET_DATA.Length, 0, OnBOOTPReceive, state);
}

SendMagicPacket()
{
    //create and send magic packet
    // this will tell the node to respond with a BOOTPPacket
}

private void OnBOOTPReceive(IAsyncResult result)
{
    StateObject state = (StateObject) result.AsyncState;
    Socket handler = state.workSocket;
    int bytesRcvd = handler.EndReceive(result);
    packet = PACKET_DATA;

    if(isValidBOOTP(packet))
    {
        SendBOOTPResponse();    
    }
    else{
        BOOTPReceive(); //keep listening for valid bootp response
    }
}

private void SendBOOTPResponse()
{
    UdpClient udpClient = new UdpClient();
    udpClient.BeginSend(packetData, packetData.Length, BROADCAST_IP, (int)UdpPort.BOOTP_CLIENT_PORT, OnBOOTPSend, udpClient);
}

private void OnBOOTPSend(IAsyncResult result)
{
    UdpClient udpClient = (UdpClient)result.AsyncState;
    int bytesSent = udpClient.EndSend(result);
    udpClient.Close();
}

我想做的就是将其转换为async-await,但仍要求我不要立即回到调用方。 我该怎么做呢? 这可能吗? 由于await-async一直传播到顶部,这将是正确的做法吗?

我认为这将是如下的伪代码:

public void StartUpdate()
{
    bool result = await SendMagicPacket();
    bool IsError = await BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
    //don't return to caller until BOOTPCommunication is completed. How do i do this?
}

您需要等待这两个任务,然后尝试以下操作:

public async Task StartUpdate()
    {
        var resultTask =  SendMagicPacket();
        var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends

        await Task.WhenAll(new[]{resultTask, isErrorTask});
        //don't return to caller until BOOTPCommunication is completed. How do i do this?
    }

//等待BOOTP / Update完成,然后再返回到调用方

您根本不需要任何异步IO,因为您想等待所有操作完成。 我假设您已经复制了一些示例代码。 大多数示例代码使用异步套接字API。

将所有内容切换到同步套接字API,您就完成了。

如果您出于某种原因希望保持异步状态,则可以切换到等待并解开该代码。 您发布的伪代码看起来是一个不错的目标。 但是,它强制周围的方法是async Task

您也可以通过使所有调用者递归异步来解决。 如果您不需要保留线程,则可以阻止该任务,并拥有一个大部分为同步的调用链。 到那时,您将失去所有异步优势。

Radin处在正确的轨道上,但我认为您想要的是这样的东西:

您需要等待这两个任务,然后尝试以下操作:

public async Task StartUpdate()
{
    var resultTask =  SendMagicPacket();
    var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends

    Task.WhenAll(new[]{resultTask, isErrorTask}).Wait(); //Wait() will block so that the method doesn't return to the caller until both of the asynchronous tasks complete.
}

允许的是SendMagicPacket和BOOTPCommunication同时启动,但是要等待BOTH完成。 使用该模式,您可以同时触发N个事件,同时使用Wait()等待所有事件完成,以便该方法本身同步返回。

暂无
暂无

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

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