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()
.
将其转换为数组
我正在尝试制作多线程网络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()
.