【问题标题】:Await doesn't give a result等待没有给出结果
【发布时间】:2016-09-13 15:09:11
【问题描述】:

好的,我有一些代码要介绍。这是NetworkStream对象的扩展方法。

public async static Task<byte[]> ReadDataAsync(this NetworkStream clientStream)
{
    byte[] data = {};

    var buffer = new byte[1024];
    if (clientStream.CanRead)
    {
        using (var ms = new MemoryStream())
        {
            try
            {
                int bytesRead;
                while (clientStream.DataAvailable && 
                  (bytesRead = await clientStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await ms.WriteAsync(buffer, 0, bytesRead);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return data;
            }

            data = ms.ToArray();
        }
    }
    else
    {
        Console.WriteLine("Closing clientStream.");
        clientStream.Close();
    }
    return data;
}

以及我尝试调用此方法的代码。

public async static Task Preform(Socket client)
{
    var stream = new NetworkStream(client);
    var data = await stream.ReadDataAsync();
    var message = await MessageFabrique.DeserializeMessage(data);

    ServerCollections.Instance.ServerIssueQueue.Add(new ServerIssue
    {
        Message = message,
        ClientStream = stream
    });
}

ReadDataAsync 方法总是将我返回到一个空数组。而在我试图反序列化数据的那一刻,有一个例外 - 因为data[0]。请帮我。如果await 保证我在需要的时候得到结果,为什么会发生这种情况?

【问题讨论】:

  • 你确定你的 catch 块中没有出现异常吗?它将返回数据[0]。
  • 您是否在控制台应用程序中运行?
  • @Sergey.quixoticaxis.Ivanov,不。我没有发现这方面的异常。
  • @EJoshuaS,是的...但是有什么问题?

标签: c# .net asynchronous networking async-await


【解决方案1】:

clientStream.DataAvailable 并不意味着未来可能会出现数据。这意味着数据现在可供阅读。摆脱它并直接读取,读取将阻塞直到数据显示或在流结束时返回 0。

【讨论】:

  • Thnx,苏格兰人。我试试看。
【解决方案2】:

Scott 的回答是对的,但是 .Net 已经照顾好你了……

你可以考虑Stream.CopyToAsync

await clientStream.CopyToAsync(ms)

对于出错的地方要少得多的代码。

【讨论】:

  • 我可以在不使用循环的情况下这样做吗?在这种情况下是 'while'?
  • @TrumanStarr,是的,CopyToAsync 将在一次操作中将所有流复制到另一个流。
  • 提示!
【解决方案3】:

除了其他答案之外,您可能还想创建一个同步上下文。详情请见this article

总结是,async/await 在控制台应用程序中的工作方式与在 UI 应用程序中的工作方式不同。 WPF 和 WebForms 应用程序默认具有同步上下文,但控制台应用程序没有。结果(实际上在文档中“宣传得很差”)是控制台应用程序中的 async/await 行为的可预测性比它在 UI 应用程序中的可预测性差,而且这可能使其在某些情况下不能“像宣传的那样”工作。

例如,在 UI 应用程序中,“异步”并不一定意味着代码在后台线程上运行。这相当于“等我准备好后再回来找我”。打个比方,考虑和 10 个人一起出去吃饭:当服务员经过时,他要求点的第一个人还没有准备好。这里有两个不好的解决方案是 a) 引入第二个服务员来等待第一个人准备好或接受其他 9 个人的订单) 或 b) 等到第一个人准备好开始接受订单。最好的办法是接受其他 9 个人的命令,然后回到第一个人那里,希望他到那时准备好。过度简化的风险基本上是异步在 UI 中的工作方式(除非您明确地将代码放在具有诸如 Task.Run 之类的后台线程上)。但是,在控制台应用程序中,当您使用异步时,无法保证代码实际运行的位置。

但是,如果您按照我链接到的文章中的描述添加同步上下文,它将以更可预测的方式运行。

【讨论】:

  • 我通过回调到Task.Run(() =&gt; ...).ConfigureAwait(false) 开始通信服务器-客户端。我认为在这种情况下我很重要。谢谢。
  • @TrumanStarr 如果您所做的只是等待结果,那么将其置于后台线程不一定会带来明显的性能优势。
猜你喜欢
  • 1970-01-01
  • 2018-11-30
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 2019-06-20
  • 2013-07-13
  • 1970-01-01
  • 2021-01-21
相关资源
最近更新 更多