问题描述
在WPF .net核心应用程序中,有以下内容:
我正在对可观察集合中的每个项目(集合中的0到1000个项目)进行api的URL调用。返回的是XML。使用XElement解析XML。可观察集合中的属性值是从XML更新的。
Task.Run用于从UI线程运行操作。 Parallel.Foreach用于在Parallel中进行呼叫。
我觉得我使解决方案过于复杂。有没有一种方法可以简化?单击按钮即可调用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());
如果要限制并发请求的数量,则可以遍历源收集器的子集以批量发送请求,也可以使用SemaphoreSlim
限制实际的并发请求的数量:
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);
}