注册表模式中的异步回复

时间:2011-05-16 18:14:13

标签: go

我正在学习,我想探索一些模式。

我想构建一个Registry组件来维护一些东西的地图,我想提供一个序列化访问它:

目前我最终得到了类似的东西:

type JobRegistry struct {
  submission chan JobRegistrySubmitRequest
  listing chan JobRegistryListRequest
}

type JobRegistrySubmitRequest struct {
  request JobSubmissionRequest
  response chan Job
}

type JobRegistryListRequest struct {
  response chan []Job
}

func NewJobRegistry() (this *JobRegistry) {
  this = &JobRegistry{make(chan JobRegistrySubmitRequest, 10), make(chan JobRegistryListRequest, 10)}

  go func() {
    jobMap := make(map[string] Job)

    for {
        select {
        case sub := <- this.submission:
            job := MakeJob(sub.request) // ....

            jobMap[job.Id] = job
            sub.response <- job.Id

        case list := <- this.listing:

            res := make([]Job, 0, 100)
            for _, v := range jobMap {
                res = append(res, v)
            }
            list.response <- res

        }

        /// case somechannel....
     }
   }()

   return
}

基本上,我将每个操作封装在一个包含的结构中 参数和响应通道。

然后我为最终用户创建了辅助方法:

func (this *JobRegistry) List() ([]Job, os.Error) {
    res := make(chan []Job, 1)
    req := JobRegistryListRequest{res}
    this.listing <- req
    return <-res, nil // todo: handle errors like timeouts
}

我决定为每种类型的请求使用一个通道,以确保类型安全。


我用这种方法看到的问题是:

  • 当一些参数/返回类型发生变化时,很多样板代码和很多地方需要修改

  • 必须做一些奇怪的事情,比如创建另一个包装器结构,以便从处理程序goroutine中返回错误。 (如果我理解正确没有元组,并且无法在通道中发送多个值,例如多值返回)

所以,我想知道这一切是否有意义,或者只是回到旧锁上。

我确信有人会找到一些使用频道的聪明方法。

1 个答案:

答案 0 :(得分:1)

我不完全确定我理解你,但我会尽力回答。

您需要一个执行发送给它的作业的通用服务。您也可能希望作业可序列化。

我们需要的是一个定义通用作业的界面。

type Job interface {
    Run()
    Serialize(io.Writer)
}

func ReadJob(r io.Reader) {...}

type JobManager struct {
    jobs map[int] Job
    jobs_c chan Job      
}

func NewJobManager (mgr *JobManager) {
    mgr := &JobManager{make(map[int]Job),make(chan Job,JOB_QUEUE_SIZE)}
    for {
        j,ok := <- jobs_c
        if !ok {break}
        go j.Run()
    }
}

type IntJob struct{...}
func (job *IntJob) GetOutChan() chan int {...}
func (job *IntJob) Run() {...}
func (job *IntJob) Serialize(o io.Writer) {...}

更少的代码,大致同样有用。

关于使用腋窝流发出信号错误,您可以随时使用辅助功能。

type IntChanWithErr struct {
    c chan int
    errc chan os.Error
}
func (ch *IntChanWithErr) Next() (v int,err os.Error) {
    select {
        case v := <- ch.c // not handling closed channel
        case err := <- ch.errc
    }
    return
}