这是一个官网上的例子,不过在此加入了自己的一些理解。
Tornado的 tornado.queues
模块实现了异步生产者/消费者模式的协程, 类似于 通过Python 标准库的 queue 实现线程模式.
一个yield Queue.get
的协程会暂停直到队列中有值,才会get到东西.
如果队列设置了最大长度,那么 yield Queue.put
的协程会暂停直到队列中有额外空间.
一个 Queue 从0开始对完成的任务进行计数. put
加计数; task_done
减少计数.
这里的网络爬虫的例子, 队列开始的时候只包含 base_url
. 当一个worker抓取到一个页面 它会解析链接并把它添加到队列中, 然后调用 task_done
减少计数一次. 最后, 当一个worker抓取到的页面URL都是之前抓取到过的并且队列中没有任务了. 于是worker调用 task_done 把计数减到0. 等待 join
的主协程取消暂停并且完成.
代码:
import time
from datetime import timedelta
from html.parser import HTMLParser
from urllib.parse import urljoin, urldefrag
from tornado import gen, httpclient, ioloop, queues
base_url = "http://www.tornadoweb.org/en/stable"
concurency = 10 # 并发数是10
async def get_links_from_url(url):
# 首先拿到页面中的数据
response = await httpclient.AsyncHTTPClient().fetch(url)
print("fetched %s " % url)
html = response.body.decode(errors='ignore')
# 然后通过页面内容爬取所有链接回来
return [urljoin(url, remov