C# 如何正确设置HttpClient的continuations?

C# 如何正确设置HttpClient的continuations?,c#,asp.net-web-api,.net-4.0,task-parallel-library,httpclient,C#,Asp.net Web Api,.net 4.0,Task Parallel Library,Httpclient,我使用的是.NET4.0,所以不能使用async/await关键字 在我费力地设置任务和延续而不是仅仅调用之后。结果,我所做的一切都是一团糟,在几十个HTTP get的工作负载下,它的运行速度慢了46%。(如果在串行或并行循环中调用工作负载,则会出现类似的性能降级) 我必须做些什么才能看到任何性能优势 //Slower code public UserProfileViewModel GetAsync(Guid id) { UserProfileViewModel obj = null;

我使用的是.NET4.0,所以不能使用async/await关键字

在我费力地设置任务和延续而不是仅仅调用之后。结果,我所做的一切都是一团糟,在几十个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);
}
//较慢的代码
public UserProfileViewModel GetAsync(Guid id)
{
UserProfileViewModel obj=null;//闭包
任务结果=client.GetAsync(id.ToString()).ContinueWith(responseMessage=>
{
Task stringTask=responseMessage.Result
.Content.ReadAsStringAsync();
任务继续=stringTask.ContinueWith(responseBody=>
{
obj=jsonvert
.DeserializeObject(responseBody.Result);
});
//这是一个子任务,在返回到父任务之前必须等待。
continuation.Wait();
});
result.Wait();
返回obj;
}
//更快的代码
public UserProfileViewModel GetSynchr(Guid id)
{
//Asych?那是什么?
HttpResponseMessage response=client.GetAsync(id.ToString()).Result;
字符串responseBody=response.Content.ReadAsStringAsync().Result;
返回JsonConvert.DeserializeObject(responseBody);
}
您使用的是“异步”方法,但所有操作都是同步进行的。这肯定不会比使用同步方法同步完成所有事情更好

看看这个:

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();
}
公共任务GetAsync(Guid id) { var uri=id.ToString(); 返回client.GetAsync(uri).ContinueWith(responseTask=> { var响应=响应任务结果; 返回response.Content.ReadAsStringAsync().ContinueWith(jsonTask=> { var json=jsonTask.Result; 返回JsonConvert.DeserializeObject(json); }); }).Unwrap(); } 请注意该方法如何返回
任务
,以及如何从该方法返回continuations。这允许您的方法几乎立即返回,为调用方提供一个处理正在运行的工作和任何需要继续的操作的句柄。返回的任务只有在完成所有操作后才能完成,其结果将是您的
UserProfileViewModel


Unwrap
方法接受一个
Task
并将其转换为
Task

您的
Unwrap
方法是一个非常糟糕的实现,特别是考虑到.NET中有一个实现可以正确地执行它。@Servy我错误地认为它只存在于.NET 4.5中。我删除了quick and dirty实现,因为它是在.NET 4.0(OP要求的版本)中。即使是这样,您的实现仍然依赖于.NET 4.5方法。更像是这样,比串行快5倍,比调用.Result快2倍。@MatthewMartin很高兴能提供帮助。:)通常,对阻止当前线程的
Wait()
Result
的任何调用都表明异步编码错误。