【问题标题】:How can I asynchronously get data from many websites, and add them to a collection?如何从多个网站异步获取数据,并将它们添加到集合中?
【发布时间】:2017-12-13 07:48:22
【问题描述】:

我正在尝试同时调用许多不同的 Web 服务并聚合数据。

我的意图是为每个网络调用创建一个任务,将一个共享容器传递给每个任务,并将每个调用的数据存储在容器中。只要我能从每个网络调用中获取数据到共享容器中,我就很高兴。

我已经创建了一个我正在尝试做的示例 - 但是,它有时会崩溃并在 Task.WaitAll 行上出现异常:“发生一个或多个错误。(源数组不够长。检查源索引、长度和数组的下限。 参数名称:sourceArray)"。

我不熟悉使用异步/等待和多线程。

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting tasks...");
            List<Task> tasks = new List<Task>();
            List<char> container = new List<char>();
            for (int i = 0; i < 80; i++)
            {
                tasks.Add(LongTask(container));
            }
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("Checkpoint 1.");
            Console.WriteLine("Tasks Finished");

            Console.ReadLine();
        }

        public static async Task<string> LongTask(List<char> container)
        {
            var client = new HttpClient();
            var text = await client.GetAsync("http://www.google.com");

            var myList = text.StatusCode.ToString().ToList();

            container.AddRange(myList);

            return text.StatusCode.ToString();
        }
    }
}

【问题讨论】:

标签: c# multithreading async-await


【解决方案1】:

在添加数据时,您可以在当前列表周围使用lock 构造也可以使用。

下面将进入班级级别

private static object _lock = new object();

这将进入你的方法

var myList = text.StatusCode.ToString().ToList();
lock(_lock)
{
  container.AddRange(myList);
}

或者你可以使用ConcurrentBag

所以在你的代码中用 this 替换 List ,在 main 方法中

ConcurrentBag<string> container = new ConcurrentBag<string>();

并在 LongTask( 方法中执行以下操作。

 var myList = text.StatusCode.ToString().ToList();               
 container.AddRange(myList);

在这里,我建议您将字符串列表列为ConcurrentBag doenst 有AddRange 方法,如果您确实编写foreach 以添加ConcurrentBag,那么其他线程也可能在两者之间添加char,而不是其中一旦全部完成,您可以将stringConcurrentBag 中取出并将其转换为char 数组或列表。

注意:ConcurrentBag&lt;T&gt; 是一个线程安全的包实现,针对同一线程将同时生产和使用包中存储的数据的场景进行了优化。

【讨论】:

  • 这不是 ConcurrentBag 的好用处,因为内部实现旨在解决一个非常具体的问题,即添加到包中的线程几乎总是检索它添加的项目的线程。您还指出,列表和锁是更有效的解决方案
  • @RichardBlewett - 刚刚更新了答案
猜你喜欢
  • 2017-10-04
  • 2013-08-05
  • 2018-07-16
  • 1970-01-01
  • 2019-03-12
  • 2021-06-05
  • 2020-07-28
  • 2015-05-24
  • 1970-01-01
相关资源
最近更新 更多