请求在调度器里排成什么队、先出哪个?这篇把内存队列、磁盘队列和优先级队列一层层拆开:priority 怎么排序、同优先级怎么出、JOBDIR 里装不下的请求去哪了,以及 2.19 默认换成的 DownloaderAwarePriorityQueue 对优先级的影响。
SCHEDULER = scrapy.core.scheduler.Scheduler SCHEDULER_PRIORITY_QUEUE = scrapy.pqueues.DownloaderAwarePriorityQueue SCHEDULER_MEMORY_QUEUE = scrapy.squeues.LifoMemoryQueue SCHEDULER_DISK_QUEUE = scrapy.squeues.PickleLifoDiskQueue SCHEDULER_START_MEMORY_QUEUE = scrapy.squeues.FifoMemoryQueue SCHEDULER_START_DISK_QUEUE = scrapy.squeues.PickleFifoDiskQueue DUPEFILTER_CLASS = scrapy.dupefilters.RFPDupeFilter 不设 JOBDIR:dequeued=21, dequeued/memory=21, enqueued=21, enqueued/memory=21 JOBDIR=<目录>:dequeued=21, dequeued/disk=21, enqueued=21, enqueued/disk=21
调度器由三层组成:优先级队列(2.19 默认 DownloaderAwarePriorityQueue)管优先级和域名,内存/磁盘队列(默认后进先出)管同优先级内的顺序,起始请求另用先进先出的队列。
产生顺序(序号-优先级):0:0 1:5 2:-3 3:10 4:0 5:5 6:-3 7:10 8:1 9:1 10:0 11:0 服务器收到的顺序: 7:10 3:10 5:5 1:5 9:1 8:1 11:0 10:0 4:0 0:0 6:-3 2:-3 → 优先级 10 的两个(3、7)最先且后产生的 7 在前;同优先级内后产生的先出(LIFO)
Request.priority 越大越先出队,同优先级内由内存队列的类型决定顺序。
服务器收到的顺序: 3:10 7:10 1:5 5:5 8:1 9:1 0:0 4:0 10:0 11:0 2:-3 6:-3
把 SCHEDULER_MEMORY_QUEUE(和磁盘队列)换成 FIFO 版本即可。
服务器收到的顺序:mem-p-1 disk-p9 disk-p5 默认(SCHEDULER_DEBUG=False)时日志里没有任何警告;SCHEDULER_DEBUG=1 时:WARNING: Unable to serialize request: <GET http://127.0.0.1:9960/mem-p-1> - reason: Function <function S.parse.<locals>.<lambda> at 0x…> is not an instance method in: <S 's' at 0x…> stats:enqueued/disk=3, enqueued/memory=1, unserializable=1
启用 JOBDIR 后请求先尝试进磁盘队列,失败(比如回调是 lambda)才退回内存队列;出队时先内存后磁盘,两者之间不比较优先级。
DownloaderAwarePriorityQueue(默认):服务器收到的顺序 B2 A2 B1 A1 B0 A0 (A=127.0.0.1 优先级 0,B=localhost 优先级 100) ScrapyPriorityQueue:服务器收到的顺序 B2 B1 B0 A2 A1 A0 (A=127.0.0.1 优先级 0,B=localhost 优先级 100)
DownloaderAwarePriorityQueue 每个域名一个子队列,选下载中请求最少的域名出队;优先级只在域名内部起作用。
-s CONCURRENT_REQUESTS_PER_IP=2:退出码 1;服务器收到 0 个请求 ValueError: "<class 'scrapy.pqueues.DownloaderAwarePriorityQueue'>" does not support CONCURRENT_REQUESTS_PER_IP
它不支持 CONCURRENT_REQUESTS_PER_IP,设了就在启动时抛 ValueError。