4

我正在编写一个库来使用 Azure 表存储。基本模式是给定的 HTTP 请求在内容流中返回一个数字结果,并在标头中返回一个指向下一组结果的指针。当从流中读取结果时,就会产生结果。我正在使用 System.Net.Http 库(以前的 Microsoft.Net.Http),它在最新版本中删除了同步版本的 HttpClient.Send 和其他同步方法。新版本使用任务。我以前用过Tasks,但不是为了这么复杂的东西,而且我很难开始。

已转换为异步模式的调用是:HttpClient.Send、response.Context.ContentReadSteam。我已经清理了代码,以便显示重要部分。

var queryUri = _GetTableQueryUri(tableServiceUri, tableName, query, null, null, timeout);
while(true) {
    var continuationParitionKey = "";
    var continuationRowKey = "";
    using (var request = GetRequest(queryUri, null, action.Method, azureAccountName, azureAccountKey))
    {
        using (var client = new HttpClient())
        {
            using (var response = client.Send(request, HttpCompletionOption.ResponseHeadersRead))
            {
                continuationParitionKey = // stuff from headers
                continuationRowKey = // stuff from headers

                using (var reader = XmlReader.Create(response.Content.ContentReadStream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "entry" && reader.NamespaceURI == "http://www.w3.org/2005/Atom")
                        {
                            yield return XElement.ReadFrom(reader) as XElement;
                        }
                    }
                    reader.Close();
                }
            }
        }
    }
    if (continuationParitionKey == null && continuationRowKey == null)
        break;

    queryUri = _GetTableQueryUri(tableServiceUri, tableName, query, continuationParitionKey, continuationRowKey, timeout);
}

下面是我成功转换的一个示例。

client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ContinueWith(task =>
    {
        using (var response = task.Result)
        {
            if (response.StatusCode == HttpStatusCode.Created && action == HttpMethod.Post)
            {
                return XElement.Load(response.Content.ReadAsStreamAsync().Result);
            }
        }
    });

有人对如何将循环/产量转换为新模式有任何建议吗?

谢谢!埃里克

4

2 回答 2

4

正如您所发现的那样,现在async的效果不是最好的。yield尽管他们做了类似的代码转换,但目标却大不相同。

有两种解决方案:一种是提供缓冲区并使用生产者/消费者类型的方法。System.Tasks.Dataflow.dll对于管理复杂代码中的缓冲区很有用。

另一种解决方案是编写一个“异步枚举器”。这在概念上更接近您的代码应该执行的操作,但此解决方案比生产者/消费者解决方案复杂得多。

“异步枚举器”类型在 Rx 的这个视频中进行了一些讨论,您可以从一个实验性的 Rx 包中下载它(请注意,即使这是由 Rx 团队完成的,它实际上并不使用 Rx)。

于 2012-02-20T14:35:00.147 回答
1

我建议将 loop\yield 转换为某种形式的输出队列,例如,就像在本文中使用BlockingCollection<T>. 因此,您的方法的调用者为您提供了一个将结果推送到的队列。

队列很方便,因为它将生产者与消费者解耦,但它只是一种选择。更一般地说,调用者为您提供了一个回调,以便为您获取的每个结果执行。该回调应该是异步的,例如,它可以启动另一个任务。

于 2012-02-20T08:36:51.207 回答