Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

golang
go

How to create a producer and consumer in Go

Mohe Ud Din Sheikh

Overview

The Producer-Consumer problem is an operating system problem. Here, the producer produces a message and passes it to the buffer. The consumer stores that message from the buffer and removes it from the buffer.

For better understanding, let’s explore an illustration.

The producer-consumer pattern

Explanation

In the illustration above, we have a producer that passes the data to a bufferThe consumer stores that data and removes it from the buffer.

Let's look at an example to learn its implementation in Go.

Example

package main

import (
    "runtime/pprof"
    "flag"
    "log"
    "fmt"
    "runtime"
    "os"
    
    
  
)

// Producer definition
type Producer struct {
    text *chan int
    done *chan bool
}

// produce start creating message and send it through channel 
func (p *Producer) produce(max int) {
    fmt.Println("Producer start message sending")
    for i := 0; i < max; i++ {
        fmt.Println("Message send by Producer ", i)
        *p.text <- i
    }
    *p.done <- true // updates when message produced
    fmt.Println("Producer message ends")
}


type Consumer struct {
    text *chan int
}

// consume reads the text channel
func (c *Consumer) consume() {
    fmt.Println("consumer start recieving message")
    for {
        message := <-*c.text
        fmt.Println("Message recieved by consumer", message)
    }
}

func main() {
    // profile flags
    cpuflag := flag.String("cpuflag", "", "update cpu profile to `file`")
    memflag := flag.String("memflag", "", "update memory profile to the `file`")

    // Get the max number from flag
    max := flag.Int("n", 4, "Show message count")

    flag.Parse()

    // To create the maximum number of cores in the processor
    runtime.GOMAXPROCS(runtime.NumCPU())

    // CPU Profile creation
    if *cpuflag != "" {
        f, err := os.Create(*cpuflag)
        if err != nil {
            log.Fatal("Enable to create CPU profile: ", err)
        }
        if err := pprof.StartCPUProfile(f); err != nil {
            log.Fatal("Enable to start CPU profile: ", err)
        }
        defer pprof.StopCPUProfile()
    }

    var text = make(chan int)  // channel send its messages
    var done = make(chan bool) // channel to intimate when production is done 

	//creating a Producer
    //Start a goroutine for Produce.produce
	producer := &Producer{text: &text, done: &done}
    go producer.produce(*max)

	//creating a Consumer
    //Start a goroutine for Consumer.consume
	consumer := &Consumer{text: &text}
	go consumer.consume()

    // End the program when the production is complete 
    <-done

    // Memory profile creation
    if *memflag != "" {
        f, err := os.Create(*memflag)
        if err != nil {
            log.Fatal("Enable to create memory id: ", err)
        }
        runtime.GC() // get update on status
        if err := pprof.WriteHeapProfile(f); err != nil {
            log.Fatal("Enable to write memory id: ", err)
        }
        f.Close()
    }
}
The program for the consumer and producer

Explanation

  • Lines 3–9: We import the runtime/pprof, flag, log, fmt, runtime, and os packages.
  • Lines 16–19: We create a channel of the int and bool types for the Producer to transfer data using the chan keyword.
  • Lines 22–30: We create a function, produce, to send messages to consumers. We terminate it on the *p.done <-true condition.
  • Lines 33–35: We create an int type channel for the Consumer to read the message.
  • Lines 38–44: We create a function named consume for the Consumer, which shows the received messages.
  • Lines 48–52: We create two flags:
    • cpuflag: This is to update the CPU profile to the file.
    • memflag: This is to update the memory profile.
  • Line 54: We use parse.flag to get the values from the flags.
  • Line 57: We use runtime.GOMAXPROCS(runtime.NumCPU()) to create the maximum cores from the processor.
  • Lines 60–69: We use the if condition to implement cpuflag and identify if any error occurs.
  • Lines 71–72: We declare the text and done variables to send a message and get an intimation on sending the message.
  • Lines 76–77: We create a variable, Producer, and call the Producer function.
  • Lines 81–82: We create a variable, Consumer, and call the Consumer function.
  • Line 85: We use <-done to end the program from the producer's side.
  • Lines 88–99: We use the if condition to implement memflag and identify if any error occurs.

RELATED TAGS

golang
go

CONTRIBUTOR

Mohe Ud Din Sheikh
Copyright ©2022 Educative, Inc. All rights reserved
RELATED COURSES

View all Courses

Keep Exploring