使用 .Result 的异步方法
Asynchronous method using .Result
以下方法循环遍历 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;
}
Does the use of .Result necessarily make the method synchronous?
它将使 与 .Result
同步阻塞的部分 ,因为它同步等待 Task
的完成(如果您的代码不t 死锁,这在具有自定义 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();
}
以下方法循环遍历 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;
}
Does the use of .Result necessarily make the method synchronous?
它将使 与 .Result
同步阻塞的部分 ,因为它同步等待 Task
的完成(如果您的代码不t 死锁,这在具有自定义 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();
}