如何正确设置HttpClient的延续?

时间:2014-09-18 18:48:03

标签: c# asp.net-web-api .net-4.0 task-parallel-library httpclient

我正在使用.NET 4.0,所以我不能使用async / await关键字。

在我费力地设置任务和延续而不是仅仅调用.Result之后,我所得到的所有努力都是一团糟,在几十个HTTP GET的工作负载上运行速度慢了46%。 (如果我在串行或并行循环中调用工作负载,我会得到类似的性能降低)

如果看到任何性能优势,我该怎么做?

//Slower code
public UserProfileViewModel GetAsync(Guid id)
{
    UserProfileViewModel obj = null;//Closure
    Task result = client.GetAsync(id.ToString()).ContinueWith(responseMessage =>
    {
            Task<string> stringTask = responseMessage.Result
                                            .Content.ReadAsStringAsync();
            Task continuation = stringTask.ContinueWith(responseBody =>
            {
                obj = JsonConvert
                     .DeserializeObject<UserProfileViewModel>(responseBody.Result);
            });
            //This is a child task, must wait before returning to parent.
            continuation.Wait();
        });
    result.Wait();
    return obj;
}

//Faster code
public UserProfileViewModel GetSynchr(Guid id)
{
    //Asych? What's is that?
    HttpResponseMessage response = client.GetAsync(id.ToString()).Result;
    string responseBody = response.Content.ReadAsStringAsync().Result;
    return JsonConvert.DeserializeObject<UserProfileViewModel>(responseBody);
}

1 个答案:

答案 0 :(得分:5)

您正在使用&#34; async&#34;方法,但同步做一切。这肯定不会比同步方法同步完成任何事情更好。

看看这个:

public Task<UserProfileViewModel> GetAsync(Guid id)
{
    var uri = id.ToString();
    return client.GetAsync(uri).ContinueWith(responseTask =>
    {
        var response = responseTask.Result;
        return response.Content.ReadAsStringAsync().ContinueWith(jsonTask =>
        {
            var json = jsonTask.Result;
            return JsonConvert.DeserializeObject<UserProfileViewModel>(json);
        });
    }).Unwrap();
}

注意该方法如何返回Task并从方法返回延续。这允许您的方法几乎立即返回,使调用者能够处理正在运行的工作任何需要发生的延续。只有完成所有操作后,返回的任务才会完成,其结果将是UserProfileViewModel

Unwrap方法需要Task<Task<UserProfileViewModel>>并将其转换为Task<UserProfileViewModel>