c# - 如何同时完成对可观察集合的 HTTP 调用?
问题描述
在 WPF .net 核心应用程序中有以下内容:
- 项目的可观察集合 (itemObservCollection)。
- 一个静态的只读 HttpClient _httpclient
- XML 响应
我正在对可观察集合中的每个项目(集合中的 0 到 1000 个项目)的 api 进行 URL 调用。返回是 XML。使用 XElement 解析 XML。可观察集合中的属性值从 XML 更新。
Task.Run 用于从 UI 线程运行操作。Parallel.Foreach 用于进行并行调用。
我觉得我使解决方案过于复杂。有没有办法简化这个?UpdateItems() 通过单击按钮调用。
private async Task UpdateItems()
{
try
{
await Task.Run(() => Parallel.ForEach(itemObservCollection, new ParallelOptions { MaxDegreeOfParallelism = 12 }, async item =>
{
try
{
var apiRequestString = $"http://localhost:6060/" + item.Name;
HttpResponseMessage httpResponseMessage = await _httpclient.GetAsync(apiRequestString);
var httpResponseStream = await httpResponseMessage.Content.ReadAsStreamAsync();
StringBuilder sb = new StringBuilder(1024);
XElement doc = XElement.Load(httpResponseStream);
foreach (var elem in doc.Descendants())
{
if (elem.Name == "ItemDetails")
{
var itemUpdate = itemObservCollection.FirstOrDefault(updateItem => updateItem.Name == item.Name);
if (itemUpdate != null)
{
itemUpdate.Price = decimal.Parse(elem.Attribute("Price").Value);
itemUpdate.Quantity = int.Parse(elem.Attribute("Quantity").Value);
}
}
}
}
catch (Exception ex)
{
LoggerTextBlock.Text = ('\n' + ex.ToString());
}
}));
}
catch (Exception ex)
{
LoggerTextBlock.Text = ('\n' + ex.ToString());
}
}
解决方案
您可以创建一组任务并使用Task.WhenAll
.
以下示例代码启动 中的每个项目的任务ObservableCollection<int>
,然后异步等待所有任务完成:
ObservableCollection<int> itemObservCollection =
new ObservableCollection<int>(Enumerable.Range(1, 10));
async Task SendAsync()
{
//query the HTTP API here...
await Task.Delay(1000);
}
await Task.WhenAll(itemObservCollection.Select(x => SendAsync()).ToArray());
如果要限制并发请求的数量,可以遍历源集合的子集以批量发送请求,或者使用 aSemaphoreSlim
来限制实际并发请求的数量:
Task[] tasks = new Task[itemObservCollection.Count];
using (SemaphoreSlim semaphoreSlim = new SemaphoreSlim(12))
{
for (int i = 0; i < itemObservCollection.Count; ++i)
{
async Task SendAsync()
{
//query the HTTP API here...
try
{
await Task.Delay(5000);
}
finally
{
semaphoreSlim.Release();
}
}
await semaphoreSlim.WaitAsync();
tasks[i] = SendAsync();
}
await Task.WhenAll(tasks);
}
推荐阅读
- java - twillio 的 whatsapp 组
- logstash - 用于 Spring Boot 日志的 Logstash 过滤器以捕获日志级别、类名
- postgresql - PostgreSQL。使用模板创建数据库。原始表空间磁盘空间上升
- kubernetes - 哪些 kubernetes 标识符最多只能包含 63 个字符?
- sql - "invalid number" occurs even after where clause - Oracle
- rust - 使用 HashMap 实现在迭代器上映射的函数的生命周期问题
- php - WooCommerce 下订单时不填写电子邮件地址
- scope - 如何访问范围之外的 rust 变量?
- directory - 如何使用目录文件夹重命名所选文件夹中的文件,并使用 Applescript 重命名所选文件夹
- ios - 以横向显示 Apple 登录视图?