当Scheduler拿不到url的 时候,不能立即退出
在webmagic的多线程抓取中有一个比较麻烦的问题:当Scheduler拿不到url的 时候,不能立即退出,需要等到没抓完的线程都运行完毕,没有新url产生时,才能退出。之前使用Thread.sleep来实现,当拿不到url 时,sleep一段时间再取,确定没有线程执行之后,再退出。
但是这种方式始终不够优雅。Java里面有wait/notify机制可以解决这种同步的问题。于是webmagic 0.4.0用wait/notify机制代替了之前的Thread.sleep机制。代码如下:
while (!Thread.currentThread().isInterrupted() && stat.get() == STAT_RUNNING) {
Request request = scheduler.poll(this);
if (request == null) {
if (threadAlive.get() == 0 && exitWhenComplete) {
break;
}
// wait until new url added
waitNewUrl();
} else {
final Request requestFinal = request;
threadAlive.incrementAndGet();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
processRequest(requestFinal);
} catch (Exception e) {
logger.error("download " + requestFinal + " error", e);
} finally {
threadAlive.decrementAndGet();
signalNewUrl();
}
}
});
}
}
private void waitNewUrl() {
try {
newUrlLock.lock();
try {
newUrlCondition.await();
} catch (InterruptedException e) {
}
} finally {
newUrlLock.unlock();
}
}
这里当线程完成之后,会调用signalNewUrl()来通知主线程,停止等待!
0.4.0发布之后,有用户问我,为什么有的时候抓完无法退出?我开始就怀疑这里可能存在线程安全问题,但是苦于无法复现。
思考了一下,有可能存在这样执行情况:
- threadAlive>0,执行
if (threadAlive.get() == 0 && exitWhenComplete)check跳过,于是准备进入waitNewUrl(); - 此时最后一个子线程执行结束,
threadAlive.decrementAndGet();和signalNewUrl();相继执行; - 此时主线程进入
waitNewUrl(),结果已无线程执行,也无人可以notify它了,于是线程一直等待…
那么似乎在lock里加入double-check就OK了?但是今天看了http://coolshell.cn/articles/4576.html这篇文章,大概意思是:出了问题不要靠猜!一定要复现并测试!
于是决定手动模拟!开启10个线程,并mock了所有部件,循环10000次去执行,代码不贴了,地址:https://github.com/code4craft/webmagic/blob/master/webmagic-core/src/test/java/us/codecraft/webmagic/SpiderTest.java。执行一下,果然到了第13次就卡住了!jstack之后,果然卡在newUrlCondition.await();这里!
然后加入double-check:
private void waitNewUrl() {
try {
newUrlLock.lock();
//double check
if (threadAlive.get() == 0 && exitWhenComplete) {
return;
}
try {
newUrlCondition.await();
} catch (InterruptedException e) {
}
} finally {
newUrlLock.unlock();
}
}
结果执行成功!至此问题解决!
经过这个例子,也大致明白了为什么wait/notify之前总是要先lock。为什么呢?有机会写一篇文章总结一下吧!
很简单,是吧?其实这篇文章只想说明一件事:出了bug不要靠猜!一定要复现并确认解决!
当Scheduler拿不到url的 时候,不能立即退出的更多相关文章
- asp.net mvc url应用
//url加密与解密string res1 = HttpUtility.UrlEncode("7Z2K5Lgk/iI="); //值是7Z2K5Lgk%2fiI%3d string ...
- (5)Quartz学习
原文:http://blog.csdn.net/zxl315/article/details/10879927 介绍Quartz Quartz是一个开源的任务调度系统,它能用来调度很多任务的执行. 运 ...
- scrapy-redis实现爬虫分布式爬取分析与实现
本文链接:http://blog.csdn.net/u012150179/article/details/38091411 一 scrapy-redis实现分布式爬取分析 所谓的scrapy-redi ...
- 大白痴学习webmagic
摘要 webmagic 学习 从头 刚刚开始学,很多东西可能理解错了,还请各位指教 一些基本类: Request:包含要爬行的url和一些附加信息,是Page的一个成员变量 主要成员变量 String ...
- scrapy-redis使用以及剖析
scrapy-redis是一个基于redis的scrapy组件,通过它可以快速实现简单分布式爬虫程序,该组件本质上提供了三大功能: scheduler - 调度器 dupefilter - URL去重 ...
- Python 经典面试题汇总之框架篇
前端和框架 1.谈谈你对http协议的认识 浏览器本质,socket客户端遵循Http协议 HTTP协议本质:通过\r\n分割的规范,请求响应之后断开链接 ==> 短连接.无状态 具体: Htt ...
- Scrapy 框架 配置文件
配置文件 基本配置 #1.项目名称,默认的USER_AGENT由它来构成,也作为日志记录的日志名 BOT_NAME = 'Amazon' #2.爬虫应用路径 SPIDER_MODULES = ['Am ...
- quartz.properties完整版
我们通常是通过quartz.properties属性配置文件(默认情况下均使用该文件)结合StdSchedulerFactory 来使用Quartz的.StdSchedulerFactory 会加载属 ...
- 315道python面试题(参考答案)
第一部分 Python基础篇 1:为什么学习Python 家里有在这个IT圈子里面,也想让我接触这个圈子,然后给我建议学的Python, 然后自己通过百度和向有学过Python的同学了解了Python ...
随机推荐
- [置顶] 让金融互联网-P2P网贷融资量增长10倍的广告宣传公益活动
我想做一件什么事?一个公益活动,所有资料都会共享出来--- 再次声明:这是一次公益,所有资料会公开. 我正在做一点事:收集各个P2P信贷公司(包括线上线下的),然后给线上P2P信贷公司做营销策略,教他 ...
- log翻硬币
若果有一组硬币,(假定有十个),每一个硬币仅仅有两个面,正面用以表示.反面用零表示. 给定目标(初始状态)1111100000 正正正正正反反反反反 (目标状态) 1000011101 正反反反反 ...
- hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )
题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到 ...
- android的JNI标准 android的NDK
转载的! Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) ...
- Python MySQLdb Mac安装遇到的问题
Mac 下使用Python 连接Mysql 数据库,使用到模块MySQLdb,各种问题都出现,搜集整理下,最后发现最关键的还是Mac 下的Python 版本问题 前置条件: 1. 已经安装mysql ...
- Android 解屏幕锁与点亮屏幕
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net ...
- 基于visual Studio2013解决C语言竞赛题之1046矩阵计算
题目 解决代码及点评 /************************************************************************/ /* 46 ...
- JSP简单练习-使用JDOM创建xml文件
注意:在编写代码前,请确保该Web文件夹下的"WEB-INF/lib"下包括jdom.jar包! <%@ page language="java" con ...
- EasyUI - Dialog 对话框
效果: html代码: 其中有class加载方式和Javascript加载方式. <!--class加载方式--> <%--<div id="dd" cla ...
- Primefaces的fileUpload组件使用
最近在学习Primefaces(当然也是项目中需要用的).在使用其fileUpload遇到了不小的困难,现总结一下供大家及我自己今后参考使用. 1.首先是使用环境配置:正常的Primefaces开发环 ...