使用.Result

时间:2015-11-28 11:14:31

标签: c# asynchronous async-await task-parallel-library httpclient

以下方法遍历postdata列表以对令牌发出多个请求,例如,每个请求都使用特定的clientID。我的问题与异步有关。我试图让令牌的调用是异步的。使用.Result是否必然使方法同步?

public async Task<string> ReturnDataFromUrl1(List<List<KeyValuePair<string, string>>> listOfPostData)
{        
   List<Task<string>> taskList = new List<Task<string>>();       
   string allTokens = "";
   List<Task<string>> downloadTasks = new List<Task<string>>();


   foreach (var postData in listOfPostData)
   {
       using (var client = new HttpClient())
       {
           client.BaseAddress = new Uri("http://localhost:23081");

           HttpContent httpContent = new FormUrlEncodedContent(postData);
           HttpResponseMessage response = client.PostAsync("/Token", httpContent).Result;

           var responsecode = (int)response.StatusCode;

           if (response.IsSuccessStatusCode)
           {
               var responseBodyAsText = response.Content.ReadAsStringAsync();

               taskList.Add(responseBodyAsText);
           }
       }
   }

    downloadTasks = taskList.ToList();            

    while (downloadTasks.Count > 0)
    {
        Task<string> firstFinishedTask = await Task.WhenAny(downloadTasks);

        downloadTasks.Remove(firstFinishedTask);

        // Await the completed task. 
        string content = await firstFinishedTask;

        allTokens = allTokens + content;
    }

    return allTokens;
}

1 个答案:

答案 0 :(得分:4)

  

使用.Result是否必然使方法同步?

它会使阻止.Result同步的部分,因为它同步等待Task的完成(如果你的代码没有死锁,这在具有自定义SynchronizationContext)的环境中非常有用。

此方法调用:

Task<string> firstFinishedTask = await Task.WhenAny(downloadTasks);

将是异步的,因为它将产生控制,直到读取第一个流并将其转换为字符串。 如果您已经有一个标记为async的方法,那么只需await该部分:

HttpResponseMessage response = await client.PostAsync("/Token", httpContent);

旁注:

我想我会对问题采取不同的方法。通常,它是网络IO,它将占用此方法的最多时间。如果可能并且没有限制,我同时进行这些网络呼叫,然后处理结果:

public async Task<string> ReturnDataFromUrlAsync(
                                List<List<KeyValuePair<string, string>>> listOfPostData)
{
    var client = new HttpClient
    {
        BaseAddress = new Uri("http://localhost:23081")
    };

    var downloadTasks = listOfPostData.Select(postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        return client.PostAsync("/Token", content);
    }).ToList();

    var tokenBuilder = new StringBuilder(downloadTasks.Count);
    while (downloadTasks.Count > 0)
    {
        var finishedTask = await Task.WhenAny(downloadTasks);
        downloadTasks.Remove(finishedTask);
        var response = await finishedTask;

        if (!response.IsSuccessStatusCode)
            continue;

        var token = await response.Content.ReadAsStringAsync();
        tokenBuilder.Append(token);
    }

    return tokenBuilder.ToString();
}

或者因为您需要所有结果才能处理令牌,所以您可以使用Task.WhenAll等待所有结果完成:

public async Task<string> ReturnDataFromUrlAsync(
                                List<List<KeyValuePair<string, string>>> listOfPostData)
{
    var client = new HttpClient
    {
        BaseAddress = new Uri("http://localhost:23081")
    };

    var downloadTasks = listOfPostData.Select(postData =>
    {
        var content = new FormUrlEncodedContent(postData);
        return client.PostAsync("/Token", content);
    });

    HttpResponseMessage[] response = await Task.WhenAll(downloadTasks);

    var tokenBuilder = new StringBuilder(response.Length);
    foreach (var element in response.Where(message => message.IsSuccessStatusCode))
    {
        tokenBuilder.Append(await element.Content.ReadAsStringAsync());
    }
    return tokenBuilder.ToString();
}