首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Golang Actor模式

Golang Actor模式
EN

Stack Overflow用户
提问于 2021-09-16 05:32:52
回答 1查看 153关注 0票数 2

这是上一个涉及完全相同主题的问题的后续内容Benefits of actor pattern in HTTP handler

下面我重复了这篇文章中的代码:

代码语言:javascript
复制
func (a *API) handleNext(w http.ResponseWriter, r *http.Request) {
    var (
        notFound   = make(chan struct{})
        otherError = make(chan error)
        nextID     = make(chan string)
    )
    a.action <- func() {
        s, err := a.log.Oldest()
        if err == ErrNoSegmentsAvailable {
            close(notFound)
            return
        }
        if err != nil {
            otherError <- err
            return
        }
        id := uuid.New()
        a.pending[id] = pendingSegment{s, time.Now().Add(a.timeout), false}
        nextID <- id
    }
    select {
    case <-notFound:
        http.NotFound(w, r)
    case err := <-otherError:
        http.Error(w, err.Error(), http.StatusInternalServerError)
    case id := <-nextID:
        fmt.Fprint(w, id)
    }
}

单个goroutine在幕后运行下面的循环,监听action通道。所有的突变都发生在这里,因为goroutine具有独占访问权,充当同步点:

代码语言:javascript
复制
func (a *API) loop() {
    for {
        select {
        case f := <-a.action:
            f()
        }
    }
}

最初的帖子质疑这种模式的效用,因为它是handleNext块底部的select循环,直到发送给action chan的函数被触发(在专用的loop goroutine中),使得对handleNext的每个调用都串行运行。对原始问题的回答说明了“所有goroutines的总和”的总体好处,但我不确定我是否理解了这一点。

我现在的预期是,如果我们有10个连接的客户端,每个客户端都调用handleNext,它们都会立即被阻止,直到单个专用loopaction chan上拉出一个项目。由于只有一个专用的handleNext例程loop用于触发操作,并且这些操作必须完全完成,下一个goroutine才能继续执行,因此永远不会并发执行多个handleNext

我知道这个模式避免了锁定的需要,因为所有的变化都会限制在loop goroutine上,但它不是也阻止了多个客户端同时工作吗?如果在loop内部对f()的调用改为go f(),那么将会并发执行handleNext函数,但这将违背该模式的目的,因为那时您将返回到需要在action函数内使用锁。

我一定是误解了这件事。

所以-我可以看到这种模式带来的好处是无锁同步,但这不是以一次只能在一个客户端上工作为代价的吗?如果这是真的,那么这与在没有锁或任何其他同步原语的情况下一次只处理一个请求有什么不同?

EN

回答 1

Stack Overflow用户

发布于 2021-09-16 12:18:16

注意,匿名函数可以启动goroutine并提前返回:

代码语言:javascript
复制
    a.action <- func() {
        gizmo, err := a.checkGizmoAvailable() // this is run synchronously
        if err != nil {
           otherErr <- err
           return
        }

        // the remainder is run asynchronously
        go func(){
            s, err := gizmo.log.Oldest()
            if err == ErrNoSegmentsAvailable {
                close(notFound)
                return
            }
            if err != nil {
                otherError <- err
                return
            }
            id := uuid.New()
            
            // this will require synchronization :
            a.pending[id] = pendingSegment{s, time.Now().Add(a.timeout), false}
            nextID <- id
        }()

        // returning here, a.loop() can start the next function
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69202823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档