Parallel.For 和网络抓取问题

Parallel.For and web scraping issues

我正在尝试制作多线程网络scraper.For我正在使用Parallel.For.Here这是我的代码:

string source = "http://www.lolsummoners.com/ladders/eune/";
        string regex_Search = "leagues/.*>(.*)</a></td>";
        List<string> user_List = new List<string>();
        int page_Begin = 1;
        int page_End = 10;

        ParallelOptions p_Option = new ParallelOptions();
        p_Option.MaxDegreeOfParallelism = 3;
        Parallel.For(page_Begin, page_End, p_Option, index =>
            {
                try
                {
                    WebClient web = new WebClient();
                    web.Encoding = Encoding.UTF8;
                    String html = web.DownloadString(source + page_Begin);
                    MatchCollection matches = Regex.Matches(html, @regex_Search);
                    foreach(Match match_Find in matches)
                    {
                        string user = match_Find.Groups[1].Value.Replace(" ", string.Empty);
                        user_List.Add(user);
                        Console.WriteLine(user);
                    }
                }
                catch(Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                page_Begin++;
            });
        Console.ReadKey();

我的问题是,如果我使用多个线程,我会 duplicates.Is 有办法解决这个问题吗?我不需要循环从同一网页获取相同的名称,这就是为什么我在 end.This 增加 page_Begin 变量就是我所说的:

您看到重复项是因为您没有将 index 用于 current 并行传递。相反,您使用的是之前定义的 page_Begin。因此,在至少有两个线程的两次传递期间,两者都将在 1 开始下载!随着增量,后续通道将下载重复项。

更改此行:

String html = web.DownloadString(source + page_Begin);

...到

String html = web.DownloadString(source + index );

并发问题

List<> 不是 thread-safe 所以你可能想使用来自 TPL 的一个不错的 thread-safe 集合,例如 ConcurrentBag<>.

MSDN:

Bags are useful for storing objects when ordering doesn't matter, and unlike sets, bags support duplicates. ConcurrentBag is a thread-safe bag implementation, optimized for scenarios where the same thread will be both producing and consuming data stored in the bag.

System.Collections.Concurrent中定义的集合都非常高效,比通常用lock(object)编写的普通集合快得多。

改变这个:

List<string> user_List = new List<string>();

...至:

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

现在您可以从任何线程添加到包中。

稍后当您完成线程处理后,您可以使用 .ToArray().

将其转换为数组