图1.14 并发爬虫架构

与串行爬虫相比,并发爬虫架构处理空队列更为复杂。由于其他进程或线程可能仍在解析网页并即将添加新的URL,因此空队列并不代表爬虫已完成任务。

为了解决这个问题,进程或线程管理器需要向报告队列为空的进程/线程发送临时休眠信号。线程管理器需要持续监控休眠线程数量;只有当所有线程都处于休眠状态时,爬虫才能终止。

1.5.3 简易并发爬虫实现

以下是一个并发爬虫程序的主线程和子线程部分代码示例。主线程负责启动子线程,并等待所有子线程执行完毕后退出。

主线程代码:

threadList = new ArrayList<thread>(THREAD_NUM);
for (int i = 0; i < THREAD_NUM; i++) {
    Thread t = new Thread(this, "Spider Thread #" + (i+1));
    t.start();
    threadList.add(t);
}
// 当前线程等待子线程退出
while (threadList.size() > 0) {
    Thread child = (Thread)threadList.remove(0);
    child.join(); // 等待该线程执行完
}
</thread>

子线程主要执行程序:

// 从TODO队列中取出待分析的URL地址,并将其放入Visited表
public synchronized NewsSource dequeueURL() throws Exception {
    while (true) {
        if (!todo.isEmpty()) {
            NewsSource newitem = (NewsSource)todo.removeFirst();
            visited.add(newitem.URL,newitem.source);
            // ...
        }
    }
}

www.52pdf.net