如何在可观察集合上并发完成 HTTP 调用?

How to concurrently complete HTTP calls on an observable collection?

在 WPF .net 核心应用程序中有以下内容:

我正在对可观察集合中的每个项目(集合中的 0 到 1000 个项目)进行 URL 调用 api。 return 是 XML。 XML 使用 XElement 进行解析。可观察集合中的 属性 值是从 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());

如果您想限制并发请求的数量,您可以遍历源集合的子集以批量发送请求,或者使用 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);
}