mit*_*med 11 c# task-parallel-library async-await
在ac #project项目中,我正在调用一个web api,问题是我在一个方法的循环中做它们.通常没有那么多,但即使我正在考虑利用并行性.
到目前为止我正在尝试的是
public void DeployView(int itemId, string itemCode, int environmentTypeId)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiUrl"]);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var agents = _agentRepository.GetAgentsByitemId(itemId);
var tasks = agents.Select(async a =>
{
var viewPostRequest = new
{
AgentId = a.AgentId,
itemCode = itemCode,
EnvironmentId = environmentTypeId
};
var response = await client.PostAsJsonAsync("api/postView", viewPostRequest);
});
Task.WhenAll(tasks);
}
}
Run Code Online (Sandbox Code Playgroud)
但是想知道这是否是正确的路径,或者我应该尝试并行整个DeployView(即使在使用HttpClient之前)
现在我看到它发布了,我认为我不能只删除变量响应,只需执行等待而不将其设置为任何变量
谢谢
通常不需要并行化请求 - 一个线程使异步请求足够(即使您有数百个请求).考虑以下代码:
var tasks = agents.Select(a =>
{
var viewPostRequest = new
{
AgentId = a.AgentId,
itemCode = itemCode,
EnvironmentId = environmentTypeId
};
return client.PostAsJsonAsync("api/postView", viewPostRequest);
});
//now tasks is IEnumerable<Task<WebResponse>>
await Task.WhenAll(tasks);
//now all the responses are available
foreach(WebResponse response in tasks.Select(p=> p.Result))
{
//do something with the response
}
Run Code Online (Sandbox Code Playgroud)
但是,您可以在处理响应时使用并行性.您可以使用以下"foreach"循环代替上述"foreach"循环:
Parallel.Foreach(tasks.Select(p=> p.Result), response => ProcessResponse(response));
Run Code Online (Sandbox Code Playgroud)
但TMO,这是异步和并行的最佳利用:
var tasks = agents.Select(async a =>
{
var viewPostRequest = new
{
AgentId = a.AgentId,
itemCode = itemCode,
EnvironmentId = environmentTypeId
};
var response = await client.PostAsJsonAsync("api/postView", viewPostRequest);
ProcessResponse(response);
});
await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)
第一个和最后一个示例之间存在重大差异:在第一个示例中,您有一个线程启动异步请求,等待(非阻塞)所有它们返回,然后才处理它们.在第二个示例中,您将连接附加到每个任务.这样,每个响应一到达就会得到处理.假设当前的TaskScheduler允许并行(多线程)执行任务,则没有响应像第一个示例那样保持空闲状态.
*编辑-如果你做决定这样做是平行的,你可以只使用一个HttpClient的实例-这是线程安全的.
你要介绍的是并发性,而不是并行性.更多关于这一点.
你的方向很好,虽然我会做一些小改动:
首先,您应该将方法标记async Task为正在使用的方法Task.WhenAll,这将返回一个等待的方法,您需要异步等待.接下来,您只需返回操作PostAsJsonAsync,而不是等待您的内部的每个调用Select.这将节省一些开销,因为它不会为异步调用生成状态机:
public async Task DeployViewAsync(int itemId, string itemCode, int environmentTypeId)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiUrl"]);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var agents = _agentRepository.GetAgentsByitemId(itemId);
var agentTasks = agents.Select(a =>
{
var viewPostRequest = new
{
AgentId = a.AgentId,
itemCode = itemCode,
EnvironmentId = environmentTypeId
};
return client.PostAsJsonAsync("api/postView", viewPostRequest);
});
await Task.WhenAll(agentTasks);
}
}
Run Code Online (Sandbox Code Playgroud)
HttpClient能够进行并发请求(请参阅@usr链接了解更多信息),因此我没有看到每次在lambda中创建新实例的原因.请注意,如果您DeployViewAsync多次使用,也许您希望保持HttpClient身边而不是每次分配一个,并在您不再需要其服务时将其丢弃.
| 归档时间: |
|
| 查看次数: |
2116 次 |
| 最近记录: |