Last active
November 11, 2022 12:36
-
-
Save rapando/53eeb154a210e68f7ae0e9392bda3b43 to your computer and use it in GitHub Desktop.
Go Routines.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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