【问题标题】:.Net core Async Await method works as synchronously.Net core Async Await 方法同步工作
【发布时间】:2021-01-25 06:37:07
【问题描述】:

我有一个关于异步等待模式的问题。我有以下代码

internal async Task<int> ConsumedBytesAsync(byte[] buffer)
{
    while(condition)
    {
        //build message
        
        if (message != null)
        {
            if (_previousRegisterMessageTask != null)
            {
                await _previousRegisterMessageTask;
            }

            _previousRegisterMessageTask = _controllers.RegisterMessageAsync(message, chunk.MessageHeader.MessageStreamId);
        }
    }
    
    return totalConsumed;
}

还有其他类的代码。

internal async Task RegisterMessageAsync(IMessage message, uint messageid)
{
    // some stuff about retrieve resposible controller

    if (controller != null)
    {
        await controller.HandleMessage(message, action);
    }
}

我想通过异步运行 RegisterMessage 来提高性能,同时开始构建下一条消息。构建下一条消息时,应该等待完成前一条消息的注册。在理想情况下,它应该可以正常工作,但实际上 _controllers.RegisterMessageAsync 方法是同步执行的。

我已经通过 Stopwatch start 和 stop 围绕该方法进行了检查(我假设经过的时间应该在 0 - 5 左右,因为应该完成的唯一操作是返回并保存 Task,但平均执行时间是 800-900这个方法的时间)和_controllers.RegisterMessageAsync中的Control.WriteLine在等待之后和将Task保存到_previousRegisterMessageTask之后(首先出现来自_controllers.RegisterMessageAsync的Control.WriteLine。)

所以请让我知道为什么该操作同步而不是异步工作,以及我可以做些什么来实现上面描述的逻辑。也许我做了错误的测试并且它是异步工​​作的? 提前致谢。

【问题讨论】:

  • while 循环对任务有等待。这使得它是连续的。 (请注意,异步和同步之间存在差异)。所以——你能在你的代码中准确地标记你想要测量的东西吗?作为MVP?因为在当前设置下,我很想将行为归咎于循环中的等待。
  • 是的,当然。正如我上面提到的,我想同时注册消息并构建下一条消息。我测量了这行的时间执行 -> _previousRegisterMessageTask = _controllers.RegisterMessageAsync(message, chunk.MessageHeader.MessageStreamId); -> 通过秒表。我认为该行的执行应该是 0-5 的经过时间,因为应该只有返回任务并保存在 _previousRegisterMessageTask 但时间不同。运行时间为 800-900,这是此方法的平均执行时间。
  • "_controllers.RegisterMessageAsync 方法同步执行。" -> 完全不正确。您将异步操作与即发即弃处理混淆了。假设HandleMessage 是异步的,那么整个代码都是异步工作的。另外,请注意 _controllers.RegisterMessageAsync 或多或少在 _previousRegisterMessageTask 被赋值时开始执行。

标签: c# asynchronous multitasking


【解决方案1】:

您需要创建一个任务列表,然后获得一个包含所有这些任务的任务:

List<Task> tasks = new List<Task>();

while (whatever) {
    task = controller.HandleMessage(message, action);
    tasks.Add(task);
}

await Task.WhenAll(tasks);

【讨论】:

    【解决方案2】:

    await 运算符暂停对封闭 async 方法的评估,直到其操作数表示的异步操作完成。如果您需要对两个以上方法进行并行评估,请不要使用await,直到您需要方法评估的结果。您可以尝试下一个模式(如果您需要按顺序处理消息)

    internal async Task<int> ConsumedBytesAsync(byte[] buffer)
    {
        Message message = await BuildMessageAsync();
        int totalConsumed = 0;
        while (condition)
        {
            Task<Message> buildNextMessage = BuildMessageAsync();
            Task registerMessage = RegisterMessageAsync(message);
            message = buildNextMessage.IsCompleted ? buildNextMessage.Result : await buildNextMessage;
            if (!registerMessage.IsCompleted)
            {
                await registerMessage;
            }
            totalConsumed++;
        }
        return totalConsumed;
    }
    
    internal async Task<Message> BuildMessageAsync()
    {
        // long running message build operation
        await Task.Delay(1000);
        return new Message { Text = DateTime.Now.ToString() };
    }
    
    internal async Task RegisterMessageAsync(Message message)
    {
        // long running message processing 
        Console.WriteLine(message.Text);
        await Task.Delay(1000);
    }
    

    about await operator

    【讨论】:

    • “等待暂停当前线程”。不对。参见例如here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 2017-05-13
    • 1970-01-01
    • 2019-12-04
    • 2020-09-10
    相关资源
    最近更新 更多