Reputation: 17762
I have a goroutine, let's call it goProcessor
, which processes requests coming in from other goroutines.
goProcessor
can only process one request at a time. If a requests, let's call it req2, comes in while goProcessor
is still processing the previous req1 request, req2 has to be discarded and will be simply lost.
I have implemented such logic using an unbuffered channel and the select
statement, but I am not sure whether there could be a simpler more elegant way to accomplish what I want. A simple example of my solution is this
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")
}
Upvotes: 2
Views: 494
Reputation: 417572
What you did is perfectly fine and clean. Only thing you could simplify on it is to use for range
in goProcessor()
like this:
for msg := range c {
// ...
}
but other than that it's idiomatic.
A "TryLock" might come to mind to use here. There is no "TryLock" in the standard lib (there are 3rd party libs for that), but using it isn't simpler or more idiomatic in your case, you have to check if TryLock()
returns true
, and you have to unlock it. And you still need a channel to send the results to the processor, so your solution is simpler and cleaner.
Upvotes: 1