我需要抓取父网页及其子网页,我遵循http://www.albahari.com/threading/part4.aspx#%5FWait%5Fand%5FPulse的 生产环境 者/消费者概念 . 另外,我使用5个线程将链接排队和出列 .
有关如何在队列长度未知的情况下,如果所有线程都已完成处理队列,我将如何结束/加入所有线程?
以下是关于我如何编码的想法 .
static void Main(string[] args)
{
//enqueue parent links here
...
//then start crawling via threading
...
}
public void Crawl()
{
//dequeue
//get child links
//enqueue child links
}
4 回答
如果所有线程都空闲(即等待队列)并且队列为空,那么您就完成了 .
处理这种情况的一种简单方法是让线程在尝试访问队列时使用超时 . 像BlockingCollection.TryTake之类的东西 . 每当
TryTake
超时时,线程会更新一个字段以说明它已空闲多长时间:然后,您可以拥有一个每15秒左右执行一次的计时器来检查所有线程的空闲计数器 . 如果所有线程都空闲了一段时间(可能是一分钟),那么计时器可以设置取消令牌 . 这将杀死所有线程 . 您的主程序也可以监控取消令牌 .
顺便说一下,你可以在没有
BlockingCollection
和取消的情况下这样做 . 你'll just have to create your own cancellation signaling mechanism, and if you'重新使用队列上的锁,你可以用Monitor.TryEnter
替换锁语法等 .还有其他几种方法可以解决这个问题,尽管它们需要对您的程序进行一些重大的重组 .
您可以在末尾将虚拟令牌排入队列,并在遇到此令牌时让线程退出 . 喜欢:
当然,我省略了
enqueue/dequeue
操作的锁 .线程可以发出信号,表示已经结束了他们的工作,例如举起一个事件,或者调用一个代表 .
如果你愿意使用Task Parallel Library,真的不需要手动处理 生产环境 者 - 消费者的东西 . 使用
AttachToParent
选项创建任务时,子任务将与父任务链接,以便在子任务完成之前不会完成 .您可以使用
Parallel.ForEach
删除一些显式任务创建逻辑 .