java - 如何在事先不知道将要处理的项目数量的情况下停止队列处理?
问题描述
假设我正在以生产者/消费者模型的形式构建一个网络爬虫。
我的爬虫有一个队列,生产者将种子 URL 加入队列。消费者从队列中读取,爬取页面中的链接,并在重复验证(使用“已处理”集合完成)后将它们排入同一队列。
我的问题是我不知道种子 URL 可以有多少页。此外,我不想让爬虫无限制地运行,并且希望threshold
完全爬取 500 个页面。
我的代码如下:
int retryCount = 0;
while(true){
if(!queue.empty()){
process(queue.poll()); // assume process method runs in multiple threads.
retryCount = 0; // reset the retry count
}else{
Thread.sleep(1000) // wait for 1 second before retrying.
if(retryCount == threshold){
break;
}
retryCount++;
}
}
案例 1:如果我的种子 URL 有 5 个页面,那么这 5 个页面会被抓取,并且在某一时刻,队列将变为空,这将在退出 while 循环之前启动重试逻辑。这也有助于我防止在抓取时出现任何网络延迟,即。它就像一个超时。
案例 2:如果我的种子 URL 有更多页面,比如 100,那么我的队列将加载 100,这反过来又会继续加载更多页面。现在如何限制页面抓取限制?
我的方法:
- 针对每个种子 URL,我维护一个计数器映射,让我知道当前处理的页面。基于此,我限制了进程调用,然后超时逻辑启动,循环退出。这里的问题是我也需要使地图线程安全,这增加了更多的复杂性。此外,这种方法似乎很老套,因为我依赖于退出的重试而不是适当的关闭。
threshold
在 while 循环中检查的带有计数的信号量。我acquire()
每次提交到process()
0 时,我都会中断循环并等待处理完成。这将主要作为上限停止,但我仍将依赖于下限停止的超时逻辑。- 使用毒丸/哨兵,这将再次成为上限。不知道如何计算出下限。
注意:我真的不能依靠队列为空来打破循环,因为它可能会导致竞争条件错误。此外,队列可以处理多个种子 URL,并且不限于一个域。
请告诉我处理这种情况的最佳方法是什么。
解决方案
推荐阅读
- mongodb - MongoDB - 更新
- c - 线程终止后的状态
- c# - 带有 ISampleProvider 的 NAudio WasapiOut 随机停止
- ios - Swift 5 Present ViewController 中途
- python - Python列表没有给出正确的结果
- arrays - Mongodb 使用 $elemMatch 到 $filter
- reactjs - 是否可以在同一个域下使用 Next.js 和 WordPress 页面?
- php - CakePHP 4、AWS Elasticsearch 7 - 请求中包含的安全令牌无效
- hibernate - JPA:使用 JoinTable 删除 OneToMany 关系的所有实体
- database - 如何使用 Oracle 12c 中的 impdp 将带有配置文件的 dmp 文件从 CDB 数据库导入 PDB 数据库实例?