- references 
- https://www.oreilly.com/library/view/learning-go/9781492077206/
 - https://go.dev/tour/concurrency/5
 - https://en.wikipedia.org/wiki/Communicating_sequential_processes
 - https://www.sciencedirect.com/topics/computer-science/communicating-sequential-process
 - https://slikts.github.io/concurrency-glossary/?id=communicating-sequential-processes-csp
 - https://medium.com/@arturkulig/communicating-sequential-processes-in-js-intro-e620688b6175
 - https://dev.to/karanpratapsingh/csp-vs-actor-model-for-concurrency-1cpg
 - https://aiochan.readthedocs.io/en/latest/csp.html
 - https://chatgpt.com/
 
 
- goals of this workshop 
- introduction to concurrency approach taken by golang 
- Communicating Sequential Processes (CSP)
 - how it differs from actor model
 
 - understanding of basic components 
- goroutine
 - channel and select
 - context
 
 - peek into concurrency primitives 
WaitGroups, mutexes, atomics
 
 - introduction to concurrency approach taken by golang 
 - workshop plan 
- task1 
- execute two requests in parallel (
fetchCustomer,fetchProduct) - add timeouts than can terminate http requests
 - return both customer and product to enable further processing
 
 - execute two requests in parallel (
 - task2 
- encapsulate heavy computation in a function that supports 
- contextual timeout
 - declarative timeout
 
 
 - encapsulate heavy computation in a function that supports 
 - task3 
- divide and conquer: split array to smaller sums, sum them in goroutines and sum partial results
 
 
 - task1 
 
- Communicating Sequential Processes (CSP) 
- mathematical theory of concurrency based on message passing via channels 
- combines the sequential thread (threaded state) abstraction with synchronous message passing communication 
- collection of independent processes with a distinct memory space 
- example: two processes may run on two cores of the same multiprocessor chip
 
 - data is exchanged between processors by the sending and receiving of messages
 
 - collection of independent processes with a distinct memory space 
 
 - combines the sequential thread (threaded state) abstraction with synchronous message passing communication 
 - gradation 
- processes 
- group of codes that can be considered as an independent entity
 - example: function
 
 - sequential processes 
- deterministically equivalent to sequential execution
 - it is possible to predict what happens next by knowing the current state
 - disclaimer: it does not mean execution from top to bottom 
- control statements like while, for, etc., are useful because they disrupt the sequential flow
 
 
 - communicating sequential processes 
- sequential processes + IO by rendezvous 
- rendezvous = synchronization mechanism where two processes come together to exchange data directly and simultaneously
 
 
 - sequential processes + IO by rendezvous 
 
 - processes 
 - vs actor model 
- actors have identities 
- processes in CSP are anonymous
 
 - actor model: asynchronous + indirect communication 
- CSP: synchronous + direct communication
 
 - actor model: no ordering guarantees across different senders 
- CSP messages are delivered in the order they were sent
 
 
 - actors have identities 
 
 - mathematical theory of concurrency based on message passing via channels 
 
- goroutine 
- based CSP
 - lightweight thread, managed by the Go runtime 
- Go runtime 
- set of kernel-level threads, each managing a local run queue (LRQ) of goroutines 
- number of threads = 
GOMAXPROCS - global run queue (GRQ) for goroutines not assigned yet to a kernel-level thread
 - work stealing to balance queues 
- example: blocking operations 
- old thread with its goroutine waiting is descheduled by the OS
 - LRQ is moved to other thread (new or from the idle pool)
 
 
 - example: blocking operations 
 
 - number of threads = 
 - program starts => Go runtime creates a number of threads and launches a single goroutine to run program
 
 - set of kernel-level threads, each managing a local run queue (LRQ) of goroutines 
 
 - Go runtime 
 - stack sizes can grow as needed
 - launched by placing the 
gokeyword before a function invocation - any values returned by the function are ignored 
- goroutines communicate using channels
 
 - most of the time has no parameters 
- captures values from the environment
 - if variable might change => pass by parameter
 
 
 - channel 
- are message boxes — stacks of messages with no specified receiver
 - act as synchronization points 
- reading and writing to a channel are synchronized operations
 - makes them safe even if they run in parallel
 
 - example 
ch := make(chan int) a := <-ch // read ch <- b // write - passing a channel to a function = passing a pointer to the channel 
- similar to how 
mapis implemented 
 - similar to how 
 - value written to a channel can be read only once 
- in particular: multiple goroutines reading same channel => value read by only one of them
 
 - convention for passing / assigning 
ch <-chan int- only reads from the channelch chan<- int- only writes to the channel- allows the Go compiler to ensure that a channel is only read from or written to by a function
 
 - default: unbuffered - only one slot 
- similar to promise 
- write => blocks until empty
 - read => blocks until non-empty
 
 - buffered: 
make(chan int, 10)- send operation will block only if the buffer is full
 - use cases 
- gather data back from a set of goroutines
 - limit concurrent usage
 - backpressure
 
 
 
 - similar to promise 
 - zero value: 
nil- read from a 
nilchannel never returns - can't be done inside select statement => program will hang
 
 - read from a 
 close(ch)- built-in function
 - calling twice => panic
 - write => panic
 - read => always succeeds 
- closed channel always immediately returns its zero value
 - buffered => remaining values will be returned in order
 
 - required only if a goroutine is reading 
- Go’s runtime can detect channels that are no longer referenced
 
 
- read from a channel by using a for-range loop: 
for v := range ch- loop continues until the channel is closed or break / return statement is reached
 
 select- allows a goroutine to wait on multiple communication operations (reading/writing) 
- it doesn't specifically allow to read/write to multiple channels simultaneously
 - lets a goroutine wait until one of the multiple channel operations can proceed
 
 - blocks until one of its cases can run 
- picks randomly from any of its cases that can go forward
 
 - prevents acquiring locks in an inconsistent order 
- select checks whether any of its cases can proceed
 - every goroutine deadlocked => runtime kills program 
fatal error: all goroutines are asleep - deadlock!
 
 - for-select loop ~ communicating over a number of channels 
for { select { case msg1 := <-ch1: fmt.Println(msg1) case msg2 := <-ch2: fmt.Println(msg2) } } - handling closed channels 
- for-select loop + nil channel 
case v, ok := <-in: if !ok { in = nil // the case will never succeed again! continue 
 - for-select loop + nil channel 
 
- allows a goroutine to wait on multiple communication operations (reading/writing) 
 
 - context 
- threadlocal doesn’t work in Go 
- goroutine can be rescheduled to different thread
 
 - example: 
ctx := context.Background() - treated as an immutable instance 
- adding information => wrapping an existing parent context with a child context
 - allows to pass information into deeper layers of the code 
- not the other way around
 
 Valuemethod checks whether a value is in a context or any of its parent contexts- linear search
 
 - context keys should not collide 
- pattern 
type productKey struct{} func ContextWithProduct(ctx context.Context, product string) context.Context { return context.WithValue(ctx, productKey{}, product) } func ProductFromContext(ctx context.Context) (string, bool) { product, ok := ctx.Value(productKey{}).(string) return product, ok } 
 - pattern 
 - can be cancellable 
- example 
ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() // must be called, otherwise resources leak - tells that it’s time to stop processing 
context.Donemethod returns a channel of typestruct{}- empty struct uses no memory
 - channel is closed when the cancel function is invoked
 - returns nil if context not cancellable
 
- example 
for { select { case // reading other channels case <-ctx.Done(): } } - std HTTP client respects cancellation
 - use cases 
- timeouts 
ctx, cancel := context.WithTimeout(context.Background(), limit) // reaching the timeout cancels the context - coordinate concurrent goroutines 
- example: cancel other goroutines when one of them errored
 
 
 - timeouts 
 
 - cause can be specified for the cancellation 
- example 
ctx, cancelFunc := context.WithCancelCause(context.Background()) defer cancelFunc(nil) // creating nil cause context.Cause(ctx) // reading cause - added in Go 1.20
 
 - example 
 
 - example 
 - convention: explicitly passed as the first parameter of a function
 
 - threadlocal doesn’t work in Go 
 
WaitGroup- similar to 
CountDownLatchin java - use case 
- used to wait for a collection of goroutines to finish executing
 - channel being written by multiple goroutines can be closed only once
 
 
- similar to 
 Once- use case 
- lazy load
 - call some initialization exactly once
 
 
- use case 
 - mutex 
- use case 
- sharing access to a field in a struct
 - nearly any other case => use channels
 
 - not reentrant 
- trying to acquire the same lock twice => deadlock
 
 - option: readers–writer mutex 
- blocks concurrency when writing
 
 
 - use case 
 - atomics 
- sync/atomic package