【问题标题】:Making sure that only one request is processed at a time and other requests incoming are discarded确保一次只处理一个请求,并丢弃其他传入的请求
【发布时间】:2020-11-24 08:55:24
【问题描述】:

我有一个goroutine,我们称之为goProcessor,它处理来自其他goroutine的请求。

goProcessor 一次只能处理一个请求。如果一个请求,我们称之为 req2,在 goProcessor 仍在处理之前的 req1 请求时进来,req2 必须被丢弃并且只会丢失。

我已经使用无缓冲通道和select 语句实现了这样的逻辑,但我不确定是否有更简单更优雅的方式来完成我想要的。我的解决方案的一个简单示例是这样的

var c = make(chan string)

func main() {

    goRequest := func(request string, delay int) {
        time.Sleep(time.Duration(delay) * time.Second)
        fmt.Printf("Here I am request %v\n", request)
        select {
        case c <- request:
            fmt.Printf("%v sent\n", request)
        default:
            fmt.Printf("%v discarded\n", request)
        }
    }

    goProcessor := func() {
        for {
            msg := <-c
            fmt.Println("received", msg)
            time.Sleep(3 * time.Second)
            fmt.Println("processed", msg)
        }
    }

    go goRequest("First req", 1)
    go goRequest("Second req", 2)
    go goRequest("Third req", 5)
    go goProcessor()

    time.Sleep(10 * time.Second)

    fmt.Println("Main has finished")
}

【问题讨论】:

  • @icza 谢谢。我正在想象一个使用某种互斥锁的解决方案,当有人在已经锁定时尝试锁定它时会出现一些错误。但找不到任何东西,所以我恢复到频道。
  • 将我的 cmets 转换为答案。

标签: go concurrency channel goroutine


【解决方案1】:

你所做的非常干净。唯一可以简化的就是在goProcessor() 中使用for range,如下所示:

for msg := range c {
    // ...
}

但除此之外,它是惯用的。

可能会想到在这里使用“TryLock”。标准库中没有“TryLock”(有3rd party libs),但在你的情况下使用它并不简单或更惯用,你必须检查TryLock()是否返回true,你有解锁它。而且您仍然需要一个通道将结果发送到处理器,因此您的解决方案更简单、更清晰。

【讨论】:

    猜你喜欢
    • 2019-05-11
    • 1970-01-01
    • 2021-08-16
    • 2017-03-17
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    相关资源
    最近更新 更多