Go concurrency visual explanation – select statement

Last week, I published an article on how to intuitively explain channels in Golang. If you're still confused about channels, check out that article first.

Go concurrency visual explanation - Channel

As a quick refresher: Partier, Candier and Stringer run a coffee shop. Partier is responsible for taking orders from customers and then passing these orders to the kitchen, where Candier and Stringer make coffee.

4a8b8c43a8b79926b670c3d1e8796628.png

Gophers' Cafe

In this article, I will visually explain selectstatements, another powerful tool for handling concurrency in Go applications. Gophers and their fictional cafe are still my companions, but this time, let’s focus on the party and the ordering part.

scene

Gopher's Cafe realized that more and more customers wanted to order coffee online through delivery apps. So, in addition to ordering in-store, they also opted for a delivery app. Partier monitors orders from both channels and queueforwards these orders to Candier and Stringer through another channel called.

select {
case order := <-appOrders:
    queue <- order
case order := <-inShopOrders:
    queue <- order
}

When there is an order on either of the two channels, the Partier fetches the order and forwards it to queuethe channel.

fe6d479e742783133996ee53b4a09910.png 69b1d1c2bc704632ec8aa92d99d6ab50.png

If there are orders on both channels, one of them will be selected. In an actual coffee shop, inShopOrdersorders from . However, in a Go application we cannot guarantee which order will be selected. Also note that selectthe execution of the statement will only select one order, and the Partier will not select two orders at a time. However, in many applications, selectstatements are often nested within forloops so that orders remaining in a previous iteration have a chance to be selected in the next iteration.

for {
    select {
    case order := <-appOrders:
        queue <- order
    case order := <-inShopOrders:
        queue <- order
    }
}

However, if both channels have orders, they will compete on a level playing field again.

5bcb1c847f1f6cec1d336f9b5758b175.png

Default

During non-peak hours, there are not many orders, and Partier spends a lot of time waiting. He figured he could use his time more efficiently by doing other things, such as clearing the table. This can defaultbe achieved by.

for {
    select {
    case order := <-appOrders:
        log.Println("There is an order coming from appOrders channel")
        queue <- order
    case order := <-inShopOrders:
        log.Println("There is an order coming from inShopOrders channel")
        queue <- order
    default:
        log.Println("There is no order on both channels, I will do cleaning instead")
        doCleaning()
    }
}

time.After()

time.After(duration)Typically selectused with to prevent permanent waits. Unlike default, time.After(duration)a normal time is created <-chan Time, waits for durationthe elapse of time, and then sends the current time to the returned channel. This channel selectis treated equally with other channels in the statement. As you can see, selectthe channels in the statement can be of different types.

shouldClose := false
closeHourCh := time.After(8 * time.Hour)


for !shouldClose {
    select {
    case order := <-appOrders:
        log.Println("There is an order coming from appOrders channel")
        queue <- order
    case order := <-inShopOrders:
        log.Println("There is an order coming from inShopOrders channel")
        queue <- order
    case now := <-closeHourCh:
        log.Printf("It is %v now, the shop is closing\n", now)
        shouldClose = true
    default:
        log.Println("There is no order on both channels, I will go cleaning instead")
        doCleaning()
    }
}


log.Println("Shop is closed, I'm going home now. Bye!")

This technique is very common when dealing with remote API calls because we have no guarantee when or if the remote server will return. With the aid of context, this is usually not necessary.

responseChannel := make(chan interface{})
timer := time.NewTimer(timeout)


select {
case resp := <-

Guess you like

Origin blog.csdn.net/weixin_37604985/article/details/132913768