使用.Result的异步方法

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

public async Task ReturnDataFromUrl1(List<List<KeyValuePair>> listOfPostData) { List<Task> taskList = new List<Task>(); string allTokens = ""; List<Task> downloadTasks = new List<Task>(); 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 firstFinishedTask = await Task.WhenAny(downloadTasks); downloadTasks.Remove(firstFinishedTask); // Await the completed task. string content = await firstFinishedTask; allTokens = allTokens + content; } return allTokens; } 

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

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

此方法调用:

 Task firstFinishedTask = await Task.WhenAny(downloadTasks); 

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

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

边注:

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

 public async Task ReturnDataFromUrlAsync( List>> 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 ReturnDataFromUrlAsync( List>> 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(); }