DEV Community

Tony Metzidis
Tony Metzidis

Posted on • Edited on

5 2

Go Nuts with Channels: Prioritize a Channel with Middleware

update Added a deadline

Channels are great because you can easily rewire them from fifos into multiplexers , funnels and fan-outs.

In this case we want to implement a priority fifo-- the P could be a TTL or value indicator.

Not much is needed, just a custom sort.Interface impl. based on your ordering field P--for priority. Then just read inChan into the buf, sort , and write to outChan

package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
    "strconv"
    "context"
)

type PriorityStruct struct {
    P    int
    name string
}

const BUFSIZE = 10

type PriorityChan chan PriorityStruct
type PriorityBuf []PriorityStruct

func (s PriorityBuf) Len() int {
    return len(s)
}
func (s PriorityBuf) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
func (s PriorityBuf) Less(i, j int) bool {
    return s[i].P < s[j].P
}

func Sender(pchan PriorityChan) {
    for {
        randNum := rand.Intn(3)
        pchan <- PriorityStruct{
            P:    randNum,
            name: "Bob-" + strconv.Itoa(randNum),
        }
        time.Sleep(10 * time.Millisecond)
    }
}

func Prioritize(ctx context.Context, inChan PriorityChan, outChan PriorityChan) {
    for {
        buf := make(PriorityBuf, BUFSIZE)
        var i int
        for i = range buf {
            select{
            case buf[i] = <-inChan:
            case <-ctx.Done():
                break
            }
            buf[i] = <-inChan
        }
        sort.Sort(buf)
        for j:= 0; j <= i; j++ {
            outChan <- buf[j]
        }
    }
}

func Receiver(rchan PriorityChan) {
    for {
        fmt.Printf("%v\n", <-rchan)
    }
}

func main() {
    inChan := make(PriorityChan)
    outChan := make(PriorityChan)

    ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(50 * time.Millisecond))
    defer cancel()
    go Sender(inChan)
    go Receiver(outChan)
    go Prioritize(ctx, inChan, outChan)
    <- time.After(5 * time.Second)
}

Enter fullscreen mode Exit fullscreen mode

Run it

go run priority-channel.go |head -n 15
{0 Bob-0}
{0 Bob-0}
{0 Bob-0}
{1 Bob-1}
{1 Bob-1}
{1 Bob-1}
{2 Bob-2}
{2 Bob-2}
{2 Bob-2}
{2 Bob-2}
{0 Bob-0}
{0 Bob-0}
{1 Bob-1}
{1 Bob-1}
{2 Bob-2}
Enter fullscreen mode Exit fullscreen mode

Check it out: https://play.golang.org/p/wWgi5rPcIwb

If you're not on go-nuts -- it's a good community of go-users .

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Retry later
Retry later