【问题标题】:Awaited method returns empty collection unless I use breakpoint inside除非我在里面使用断点,否则等待的方法返回空集合
【发布时间】:2016-04-19 10:05:39
【问题描述】:

我正在用 C# 编写一个程序,它将接收来自其他程序的消息,它需要读取消息,并且在某些情况下准备和发送响应。 我编写了这个方法来处理单个消息,我根据它的类型异步调用它(使用await)或同步调用它。

public async void HandleMessage(Message message)
{
    IEnumerable<Tuple<Message, ulong>> responses;
    try
    {
        if (!_communicateTypesToHandleSync.Contains(message.GetType()))
        {
             responses = await Task.Run(() => _requestHandler.HandleRequest(message));
        }
        else
        {
            responses = _requestHandler.HandleRequest(message);
        }
        foreach (var response in responses)
        {
            CSMessageHandler.AddMessageToSend(response.Item1, response.Item2);
        }
    }
    catch (Exception ex)
    {
        _logger.Error(ex, "Error while handling message");
    }
}

问题是使用 await 调用 HandleRequest 似乎总是返回一个空集合(我用条件断点检查了它)。 我试图调试它,当我终于发现发生了什么时,我在HandleRequest 的末尾设置了一个断点,只有当集合不为空时才会停止。在此断点处代码执行停止,当我从 HandleRequest 退出时,即使在 HandleMessage 中,我也没有空的 responses

【问题讨论】:

  • 等待同步方法是一种不好的代码实践;也停止在此上下文中使用 Task.Run 。看this精彩视频。
  • @JeroenHeier 用几句话概括一下怎么样。 16 分钟对我来说太长了……
  • 这没有任何意义。这是一个什么样的应用程序?调用代码是什么?
  • 我真的怀疑你是在使用 await 调用 void 方法。贴出更完整的代码。

标签: c# asynchronous async-await


【解决方案1】:

HandleMessage 应该返回一个 Task 如果 void 或 Task&lt;IEnumerable&lt;Tuple&lt;Message, ulong&gt;&gt;&gt; 如果您想返回IEnumerable&lt;Tuple&lt;Message, ulong&gt;&gt;。除非是委托,否则不应使用 void。

你的代码应该是

public async Task<IEnumerable<Tuple<Message, ulong>>> HandleMessage(Message message)
{
    IEnumerable<Tuple<Message, ulong>> responses;
    try
    {
        if (!_communicateTypesToHandleSync.Contains(message.GetType()))
        {
             responses = await Task.Run(() => _requestHandler.HandleRequest(message));
        }
        else
        {
            responses = _requestHandler.HandleRequest(message);
        }
        foreach (var response in responses)
        {
            CSMessageHandler.AddMessageToSend(response.Item1, response.Item2);
        }

        return responses;
    }
    catch (Exception ex)
    {
        _logger.Error(ex, "Error while handling message");
    }
}

你的电话应该是

await HandleMessage(Message message);

由于该方法是 void,当您调用 HandleMessage 时,它不会被等待。该方法在 1 个线程上输入,然后您执行 Task.Run 以启动另一个线程。当第二个线程启动时,线程 1 被释放并继续在调用函数上运行。

例如:

//do one thing
HandleMessage(message);
//Do other work

Task.Run 启动另一个线程时,线程 1 将在被释放时继续执行其他工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-28
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多