爬虫进阶:框架功能完善-多爬虫实现之使用gevent的Pool实现异步并发

未匹配的标注

使用gevent的Pool实现异步并发

为什么使用gevent

对于I/O密集型任务,gevent能对性能做很大提升的,协程的创建、调度开销都比线程小的多。

通过配置文件设置属性,来判断所使用的异步方式

# 异步方式  thread、coroutine
ASYNC_TYPE = 'coroutine'

让gevent的Pool和线程池Pool的接口一致

因此需要单独对gevent的Pool进行一下修改,具体如下: 在scrapy_plus下创建async包,随后创建coroutine.py模块

# scrapy_plus/async/coroutine.py
'''
由于gevent的Pool的没有close方法,也没有异常回调参数
引出需要对gevent的Pool进行一些处理,实现与线程池一样接口,实现线程和协程的无缝转换
'''
from gevent.pool import Pool as BasePool
import gevent.monkey
gevent.monkey.patch_all()    # 打补丁,替换内置的模块


class Pool(BasePool):
    '''协程池
    使得具有close方法
    使得apply_async方法具有和线程池一样的接口
    '''
    def apply_async(self, func, args=None, kwds=None, callback=None, error_callback=None):
        return super().apply_async(func, args=args, kwds=kwds, callback=callback)

    def close(self):
        '''什么都不需要执行'''
        pass

在引擎中使用上:

# scrapy_plus/core/engine.py
import time
import importlib
from datetime import datetime

from scrapy_plus.http.request import Request    # 导入Request对象
from scrapy_plus.utils.log import logger    # 导入logger
from scrapy_plus.conf import settings

# 判断使用什么异步模式,改用对应的异步池
if settings.ASYNC_TYPE == 'thread':
    from multiprocessing.dummy import Pool    # 导入线程池对象
elif settings.ASYNC_TYPE == 'coroutine':
    from scrapy_plus.async.coroutine import Pool
else:
    raise Exception("不支持的异步类型:%s, 只能是'thread'或者'coroutine'"%settings.ASYNC_TYPE)

# 注意:
# 由于打patch补丁是为了替换掉socket为非阻塞的
# 而下载器中正好使用了requests模块,如果在这之后导入协程池,会导致requests中使用的socket没有被替换成功
# 从而有可能导致使用出现问题
from .scheduler import Scheduler
from .downloader import Downloader

class Engine(object):
    ......

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~