Skip to content

Instantly share code, notes, and snippets.

@rapando
Last active November 11, 2022 12:36
Show Gist options
  • Save rapando/53eeb154a210e68f7ae0e9392bda3b43 to your computer and use it in GitHub Desktop.
Save rapando/53eeb154a210e68f7ae0e9392bda3b43 to your computer and use it in GitHub Desktop.
Go Routines.
package main
import (
"fmt"
"log"
"sync"
"time"
)
type Result struct {
Answer int
WorkerNumber int
Err error
}
// ** WHEN WORKING WITH GOROUTINES, ORDER OF PROCESSING DATA IS IGNORED
// goroutines
// there 2 ways of dealing with goroutines.
// channels & waitgroups
// **** date and time formatting in go:
// https://www.educative.io/answers/formatting-and-parsing-datetime-in-golang
// 2006 january 2nd, 3:04:05pm
//
// 1. channels are better suited when you're using goroutines to process data.
// 2. waitgroups are better suited when running more than 1 function concurrently, especially,
// if both functions run forever e.g an API and rabbitmq Consumer.
func main() {
// in this case, we can use waitgroups, because we are not processing any data with the two goroutines.
// RECOMMENDED WAY
/*
var wg sync.WaitGroup
wg.Add(2)
go consumer(&wg)
go api(&wg)
wg.Wait()
*/
// you can also use a channel to call functions that run forever
// NOT RECOMENDED
/*
var start = make(chan bool)
go api_with_channel()
go consumer_with_channel()
<-start
*/
// now say we want to process a lot of data, e.g multiply the ages by 3
var startTime = time.Now()
var ages = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// processing in a linear manner takes 10 seconds
/*
for _, age := range ages {
fmt.Println(age, multiplyBy3(age))
}
fmt.Println("took ", time.Since(startTime))
*/
// Lets process with channels
// 1. create a job channel and a result channel
// jobs channel will store the data that we're going to process
// results channel will store the results
var length = len(ages)
var jobs = make(chan int, length)
var results = make(chan Result, length)
// 2. create workers : workers are basically the number of goroutines.
// workers <= length of the jobs
// if you're using external resources e.g db, rabbitmq
// workers < number of connections
var workers = 3
if workers > length {
workers = length
}
// 3. copy the data into the jobs channel
for _, age := range ages {
jobs <- age
}
// 4. call the workers
for i := 0; i < workers; i++ {
go worker(i, jobs, results)
}
fmt.Printf("skjfhkdsj")
// 5. read all the results
for i := 0; i < length; i++ {
r := <-results
fmt.Printf("answer=%d, worker=%d, err=%v\n", r.Answer, r.WorkerNumber, r.Err)
}
fmt.Println("took ", time.Since(startTime))
}
func api(wg *sync.WaitGroup) {
defer wg.Done()
var counter = 0
for { // infinite loop to simulate an API
counter++
log.Printf("api : \t%s", time.Now().Format("15:04:05"))
time.Sleep(time.Second)
if counter == 5 {
break
}
}
}
func consumer(wg *sync.WaitGroup) {
defer wg.Done()
var counter = 0
for { // infinite loop to simulate an Consumer
counter++
log.Printf("consumer : \t%s", time.Now().Format("15:04:05"))
time.Sleep(time.Second)
if counter == 3 {
break
}
}
}
func api_with_channel() {
for { // infinite loop to simulate an API
log.Printf("api : \t%s", time.Now().Format("15:04:05"))
time.Sleep(time.Second)
}
}
func consumer_with_channel() {
for { // infinite loop to simulate an Consumer
log.Printf("consumer : \t%s", time.Now().Format("15:04:05"))
time.Sleep(time.Second)
}
}
// we are reading FROM a channel of integers therefore for jobs
// jobs <- chan int
// we are writing integers into a channel (results)
// results chan <- int
func worker(i int, jobs <-chan int, results chan<- Result) {
for j := range jobs {
// fmt.Printf("worker %d processed %d, answer=%d\n", i, j, answer)
var answer int
var err error
if j > 6 {
err = fmt.Errorf("we don't accept numbers above 6 (%d)", j)
} else {
answer = multiplyBy3(j)
}
results <- Result{
Answer: answer,
WorkerNumber: i,
Err: err,
}
}
}
func multiplyBy3(age int) int {
time.Sleep(time.Second)
return age * 3
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment