加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Go语言网络爬虫组件注册器

发布时间:2020-12-16 18:01:40 所属栏目:大数据 来源:网络整理
导读:在讲解下载器接口设计时,我们介绍过组件注册方面的设计和组件注册器接口 Registrar,它声明在 module 包中。根据前面的接口描述,我们会让组件注册器按照类型存储已注册的组件。该接口的声明如下: //细件注册器的实现类型type myRegistrar struct { //组件
在讲解下载器接口设计时,我们介绍过组件注册方面的设计和组件注册器接口 Registrar,它声明在 module 包中。根据前面的接口描述,我们会让组件注册器按照类型存储已注册的组件。该接口的声明如下:
//细件注册器的实现类型
type myRegistrar struct {
    //组件类型与对应组件实例的映射
    moduleTypeMap map[Type]map[MID]Module
    //组件注册专用读写锁
    rwlock sync.RWMutex
}
在组件注册器的实现类型 myRegistrar 中只有两个字段,一个用于分类存储组件实例,另一个用于读写保护。由于注册和注销组件实例的动作肯定不会太频繁,所以这里简单地使用读写锁实施保护就足够了。

moduleTypeMap 表示一个双层的字典结构,其中第一层提供了分类型注册和获取组件实例集合的能力,而第二层则负责存储组件实例集合。

Registrar 接口的 Register 方法只需做两件事:检查参数和注册组件实例。在检查参数时,Register 方法用到了 module 包中的一些工具类方法和变量。该方法的实现如下:
func (registrar *myRegistrar) Register(module Module) (bool,error) {
    if module == nil {
        return false,errors.NewIllegalParameterError("nil module instance")
    }
    mid := module.ID()
    parts,err := SplitMID(mid)
    if err != nil {
        return false,err
    }
    moduleType := legalLetterTypeMap[parts[0]]
    if !CheckType(moduleType,module) {
        errMsg := fmt.Sprintf("incorrect module type: %s",moduleType)
        return false,errors.NewIllegalParameterError(errMsg)
    }
    //省略部分代码
}
前面已经介绍过 NewIllegalParameterError 和 SplitMID 函数。legalLetterTypeMap 变量是一个以组件类型字母为键、以组件类型为元素的字典,是前面介绍的 legalTypeLetterMap 的反向映射。CheckType 函数的功能是检查从组件 ID 解析出来的组件类型与组件实例的实际类型是否相符。

如果所有检查都通过了,那么 Register 方法就会把组件实例存储在 moduleTypeMap 中。当然,肯定会在 rwlock 的保护之下操作 moduleTypeMap。

Unregister 方法会把与给定的组件 ID 对应的组件实例从 moduleTypeMap 删除掉。在真正进行查找和删除操作前,它会先通过调用 SplitMID 函数检查那个组件 ID 的合法性。

Get 方法的实现包含负载均衡的策略,并返回最“空闲”的那个组件实例:
// Get用于获取一个指定类型的组件的实例。
//本函数会基于负载均衡策略返回实例
func (registrar *myRegistrar) Get(moduleType Type) (Module,error) {
    modules,err := registrar.GetAllByType(moduleType)
    if err != nil {
        return nil,err
    }
    minScore := uint64(0)
    var selectedModule Module
    for _,module := range modules {
        SetScore(module)
        if err != nil {
            return nil,err
        }
        score := module.Score()
        if minScore == 0 || score < minScore {
            selectedModule = module
            minScore = score
        }
    }
    return selectedModule,nil
}
该方法先调用注册器的 GetAllByType 方法以获得指定类型的组件实例的集合,然后在遍历它们时计算其评分,并找到评分最低者,最后返回。其中 SetScore 是一个工具类函数,它通过组件实例的 ScoreCalculator 方法获得它的评分计算器。若该方法返回 nil,则使用默认的计算函数。计算其评分后,再通过组件实例的 SetScore 方法设置评分。

为了让 *myRegistrar 类型成为 Registrar 接口的实现类型,还需要实现它的 GetAllByType、GetAll 和 Clear 方法。不过这几个方法的实现都非常简单,这里就不展示了。这里需要注意的是对 rwlock 字段的合理运用。

一旦把所有方法都编写好,下面这个函数就可以编译通过了:
//用于创建一个组件注册器的实例
func NewRegistrar() Registrar {
    return &myRegistrar{
        moduleTypeMap: map[Type]map[MID]Module{},}
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读