我正在构建一个抓取工具。我的目标是启动 X 个浏览器(其中 X 是线程数),然后通过将列表分成 X 个部分来继续抓取每个浏览器的 URL 列表。
我决定使用 3 个线程(3 个浏览器)和 10 个 URL 列表。
问题:如何像这样在浏览器之间分隔每个任务:
Browser1 抓取列表中从 0 到 3 的项目
Browser2 将列表中的项目从 4 抓取到 7
Browser3 将列表中的项目从 8 抓取到 10
所有浏览器都应该同时抓取传递的 URL 列表。
我已经有了这个 BlockingCollection
:
BlockingCollection<Action> _taskQ = new BlockingCollection<Action>();
public Multithreading(int workerCount)
{
// Create and start a separate Task for each consumer:
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew(Consume);
}
public void Dispose() { _taskQ.CompleteAdding(); }
public void EnqueueTask(Action action) { _taskQ.Add(action); }
void Consume()
{
// This sequence that we’re enumerating will block when no elements
// are available and will end when CompleteAdding is called.
foreach (Action action in _taskQ.GetConsumingEnumerable())
action(); // Perform task.
}
public int ItemsCount()
{
return _taskQ.Count;
}
可以这样使用:
Multithreading multithread = new Multithreading(3); //3 threads
foreach(string url in urlList){
multithread.EnqueueTask(new Action(() =>
{
startScraping(browser1); //or browser2 or browser3
}));
}
我需要在抓取之前创建浏览器实例,因为我不想在每个线程都启动一个新浏览器。
最佳答案
考虑到 Henk Holtermans 的评论,您可能想要最大速度,即让浏览器尽可能忙碌,使用这个:
private static void StartScraping(int id, IEnumerable<Uri> urls)
{
// Construct browser here
foreach (Uri url in urls)
{
// Use browser to process url here
Console.WriteLine("Browser {0} is processing url {1}", id, url);
}
}
主要是:
int nrWorkers = 3;
int nrUrls = 10;
BlockingCollection<Uri> taskQ = new BlockingCollection<Uri>();
foreach (int i in Enumerable.Range(0, nrWorkers))
{
Task.Run(() => StartScraping(i, taskQ.GetConsumingEnumerable()));
}
foreach (int i in Enumerable.Range(0, nrUrls))
{
taskQ.Add(new Uri(String.Format("http://Url{0}", i)));
}
taskQ.CompleteAdding();
关于c# - 如何在多线程时传递不同的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25348803/