0% found this document useful (0 votes)
29 views54 pages

L7 Concurrency in Go

Lecture 7 covers concurrency and parallelism in Go, emphasizing the differences between the two concepts and introducing key features such as goroutines and channels. It discusses the importance of communication in concurrent programming, the challenges faced, and the implications of Amdahl's Law on parallel execution. The lecture also highlights the Go memory model and the use of the sync package for managing shared memory.

Uploaded by

Chang Jingyan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views54 pages

L7 Concurrency in Go

Lecture 7 covers concurrency and parallelism in Go, emphasizing the differences between the two concepts and introducing key features such as goroutines and channels. It discusses the importance of communication in concurrent programming, the challenges faced, and the implications of Amdahl's Law on parallel execution. The lecture also highlights the Go memory model and the use of the sync package for managing shared memory.

Uploaded by

Chang Jingyan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 54

Lecture 7

Concurrency in Go
CS3211 Parallel and Concurrent Programming
Outline
• Revisiting concurrency vs. parallelism
• Types of parallelism
• Amdahl’s Law
• Concurrency and communication with Go
• Goroutines, channels in Go
• The sync package
• The Go memory model

CS3211 L7 - Concurrency in Go 2
Why study concurrency?
• Not a new concept!
• Traditionally concurrency was achieved through task switching

• Increased prevalence of computers that can genuinely run multiple


tasks in parallel rather than just giving the illusion of doing so
• Illusion of concurrency vs. true concurrency

CS3211 L7 - Concurrency in Go 3
Concurrency vs. Parallelism
Concurrency Parallelism
• Two or more tasks can start, run, • Two or more tasks can run
and complete in overlapping (execute) simultaneously, at the
time periods exact same time
• They might not be running • Tasks do not only make progress,
(executing on CPU) at the same but they also actually execute
instant simultaneously
• Two or more execution flows make
progress at the same time by
interleaving their executions or by
executing instructions (on CPU) at
exactly the same time

Structure CS3211 L7 - Concurrency in Go


Execution 4
Concurrency in Programming Languages
• We write concurrent code
• We hope that our code will run in parallel
• Ways of achieving concurrency:
Until now in CS3211 (C++): Next in CS3211 (Go):
Model your program in terms of threads Model your program in terms of tasks
Synchronize the access to the memory between Synchronize the tasks by making them communicate
them
Use thread pools to limit the number of threads that
must be handled by the machine

CS3211 L7 - Concurrency in Go 5
Programming languages with mascots!
• Go!

CS3211 L7 - Concurrency in Go 6
Go
• Programming language announced at Google in 2009
• Compiled programming language
• Statically typed
• (Partially) syntactically similar to C, but with
• Memory safety
• Garbage collection
• CSP-style concurrency
• Compilers & tools: gc, gccgo, gollvm

CS3211 L7 - Concurrency in Go 7
Concurrent designs
• Types of parallelism
• Limiting factors for parallelism

CS3211 L7 - Concurrency in Go 8
Solutions to a problem Sequential

1. With only one gopher


this will take too long

More processes
2. More gophers are not
enough
• need more carts

3. More gophers and


carts Processes can run same task: embarrassingly parallel, data parallelism
• bottlenecks at the pile
and incinerator
• need to synchronize the
gophers.

CS3211 L7 - Concurrency in Go 9
*https://talks.golang.org/2012/waza.slide
Concurrent composition
• Not automatically parallel!
• However, it's automatically parallelizable!
• This can be twice as fast when running in parallel

Same task: embarrassingly parallel, data parallelism

CS3211 L7 - Concurrency in Go 10
Concurrent designs
• Three gophers in action,
but with (likely) delays Break the work into tasks: aka pipeline parallelism
• Finer-grained concurrency
• Four distinct gopher
procedures:
• load books onto cart
• move cart to incinerator
• unload cart into
incinerator
• return empty cart
• Enables different ways to
parallelize

CS3211 L7 - Concurrency in Go 11
Concurrency enabled more parallelization
• Now parallelize on the other axis
• 8 gophers

CS3211 L7 - Concurrency in Go 12
Other concurrent designs
• Design 1

• Design 2

CS3211 L7 - Concurrency in Go 13
Back to computing
• In our book transport problem, substitute:
• book pile => web content
• gopher => CPU
• cart => rendering, or networking
• incinerator => proxy, browser, or other consumer
• It becomes a concurrent design for a scalable web service
• Gophers are serving web content

CS3211 L7 - Concurrency in Go 14
Take-away points
• There are many concurrent designs
• Many ways to break the processing down
• Finer level of granularity enables our program to scale
dynamically when it runs to the amount of parallelism
possible on the program’s host
• Amdahl’s law in action!

CS3211 L7 - Concurrency in Go 15
Types of parallelism
• Task parallelism
• Do the same work faster
• Data parallelism
• Embarrassingly parallel algorithms
• Do more work in the same amount of time

CS3211 L7 - Concurrency in Go 16
Task Dependency Graph
• Can be used to visualize and evaluate the task decomposition strategy
• A directed acyclic graph:
• Node: Represent each task, node value is the expected execution time
• Edge: Represent control dependency between task

• Properties:
• Critical path length: maximum (slowest) completion time
• Degree of concurrency = Total Work / Critical Path Length
• An indication of amount of work that can be done concurrently

CS3211 L7 - Concurrency in Go 17
An example

*https://medium.com/@dustinstansbury/understanding-apache-airflows-key-concepts-a96efed52b1a

CS3211 L7 - Concurrency in Go 18
Concurrent Programming Challenges
• Finding enough concurrency
• Granularity of tasks
• Coordination and synchronization

CS3211 L7 - Concurrency in Go 19
Parallel Program: Speedup
• Measure the benefit of parallelism
• A comparison between sequential and parallel execution time

𝑻𝑻𝒃𝒃𝒃𝒃𝒃𝒃𝒃𝒃_𝒔𝒔𝒔𝒔𝒔𝒔 𝒏𝒏
𝑺𝑺𝒑𝒑 𝒏𝒏 =
𝑻𝑻𝒑𝒑 𝒏𝒏

CS3211 L7 - Concurrency in Go 20
Amdahl's Law (1967)

Speedup of parallel execution is limited by the fraction of


the algorithm that cannot be parallelized (f).

• f (0 ≤ f ≤ 1) is called the sequential fraction


• Also known as fixed-workload performance

• The most well-known law for discussing speedup performance


• Applicable at all levels of parallelism

CS3211 L7 - Concurrency in Go 21
Amdahl’s Law: Implication
• Sequential execution time:

𝒇𝒇 × 𝑻𝑻∗ 𝒏𝒏 𝟏𝟏 − 𝒇𝒇 × 𝑻𝑻∗ 𝒏𝒏
• Parallel execution time:

𝟏𝟏 − 𝒇𝒇 × 𝑻𝑻∗ 𝒏𝒏
𝒇𝒇 × 𝑻𝑻∗ 𝒏𝒏
𝒑𝒑

𝑻𝑻∗ 𝒏𝒏 𝟏𝟏 𝟏𝟏
𝑺𝑺𝒑𝒑 𝒏𝒏 = = ≤
𝟏𝟏 − 𝒇𝒇 𝟏𝟏 − 𝒇𝒇 𝒇𝒇
𝒇𝒇 × 𝑻𝑻∗ 𝒏𝒏 + 𝑻𝑻∗ 𝒏𝒏 𝒇𝒇 +
𝒑𝒑 𝒑𝒑
CS3211 L7 - Concurrency in Go 23
Outline
• Revisiting concurrency vs. parallelism
• Types of parallelism
• Amdahl’s Law
• Concurrency and communication with Go
• Goroutines, channels in Go
• The sync package
• The Go memory model

CS3211 L7 - Concurrency in Go 25
Concurrency + Communication
• Go model – based on Communicating Sequential Processes (CSP)*
• Concurrency: structure a program by breaking it into pieces that can be
executed independently
• Communication: coordinate the independent executions
*C. A. R. Hoare: Communicating Sequential Processes (CACM 1978)
• Ideas of CSP
• Refined to process calculus
• Can be used to reason about program correctness

CS3211 L7 - Concurrency in Go 26
Abstractions in Go
Concurrency Communication

• Goroutines • Channels
• A function running independently • Goroutines can write to and read
• Spin up (start) a goroutine using from a channel
go function_name channel<-
• Run on OS threads <-channel
• select statements

CS3211 L7 - Concurrency in Go 27
Abstractions in Go
Concurrency Communication

• Goroutines • Channels
• A function running independently • Goroutines can write to and read
• Spin up (start) a goroutine using from a channel
go function_name channel<-
• Run on OS threads <-channel
• select statements

• Tasks • Dependencies

CS3211 L7 - Concurrency in Go 28
Goroutines
• Function running independently
• In the same address space as other goroutines
• Like & in shell
• Cheaper than threads
• Goroutines follow the fork-join model

CS3211 L7 - Concurrency in Go 29
Running Goroutines
• Runtime multiplexes goroutines onto OS threads
• Automatic scheduling – mapping M:N
• Decouples concurrency from parallelism
• Goroutine is a special class of coroutine (concurrent
subroutine)
• When a goroutine blocks
• but no other goroutine blocks
• Preemptable: Go’s runtime can suspend them

CS3211 L7 - Concurrency in Go 30
Goroutines example
• Line 3: the main goroutine is automatically
created and started when the process
begins
• Line 4: start a goroutine using keyword go
• Line 8: the print might never happen
because the main goroutine finishes
execution before sayHello completes

• Line 11: anonymous function

CS3211 L7 - Concurrency in Go 31
Goroutines are lightweight
• A newly minted goroutine is given a few kilobytes, which is almost
always enough
• When it isn’t, the runtime grows (and shrinks) the memory for storing the
stack automatically
• The CPU overhead averages about three cheap instructions per
function call
• It is practical to create hundreds of thousands of goroutines in the
same address space
• Goroutines are not garbage collected!
• Programmer should prevent goroutine leaks

CS3211 L7 - Concurrency in Go 32
Goroutines
• Line 12: Join point
• Line 7: The goroutine is running a closure that has closed over the
iteration variable salutation

Go runtime is observant enough to know that a reference to the salutation


variable is still being held, and therefore will transfer the memory to the heap so
that the goroutines can continue
CS3211 L7 - Concurrency in Go to access it. 33
Goroutines
• Line 19: write this loop is to pass a copy of salutation into the
closure

CS3211 L7 - Concurrency in Go 34
Potential issues with shared memory
• Need to synchronize access to shared memory locations
• Similar to what we did in C++
• sync package
• Don’t rely on shared memory for memory locations that are modified
• Never modify a shared memory location
• Use channels instead of modifying shared memory

CS3211 L7 - Concurrency in Go 35
Channels
• Serves as a conduit for a stream of information
• Like the pipe (|) in shell
• Values may be passed along the channel, and then read out
downstream
• Pass a value into a chan variable, and then somewhere else in your program
read it off the channel
• No knowledge is required about the other parts of your program that
work with the channel
• A channel is a reference to a place in memory where the channel
resides
• Channels (references of channels) can be passed around your program

CS3211 L7 - Concurrency in Go 36
Channels
• Typed
• Bi-/uni- directional
• Blocking
• Write to a channel that is full waits until the channel has been emptied
• Read from a channel that is empty waits until at least one item is placed on it
• Can cause deadlocks!

CS3211 L7 - Concurrency in Go 37
Creating a channel
• Lines 4-5: declare and create
a bidirectional channel using
built-in make function

• Lines 8-9: declare a


unidirectional channel

• Line 22: receive will block


until timerChan delivers.
• Value sent is other goroutine's
completion time

CS3211 L7 - Concurrency in Go 38
Blocking operations
• Lines 23, 26: blocking read
and write
• Line 25: ok Boolean indicates
whether the read was
• a value generated by a write, or
• a default value generated from
a closed channel

• Line 33: reading from a closed


channel
• Allowed any number of times

CS3211 L7 - Concurrency in Go 39
Synchronizing using channels
• Line 48: ranging over a channel
• The loop doesn’t need an exit
criteria

• Line 62: instead of writing n times


to the channel to unblock each
goroutine, you can simply close
the channel

CS3211 L7 - Concurrency in Go 40
Buffered channel
c := make(chan rune, 4)

Blocked until
A is read

CS3211 L7 - Concurrency in Go 41
CS3211 L7 - Concurrency in Go 42
Ownership of a channel
• Owner is the goroutine that instantiates, writes, and closes a channel
• Useful when reasoning about program correctness
• Unidirectional channels
• Owners have a write-access view into the channel (chan or chan<-)
• Utilizers only have a read-only view into the channel (<-chan)
Owner should Consumer should
• Instantiate the channel • Know when a channel is closed
• Perform writes, or pass ownership to • Responsibly handle blocking for any reason
another goroutine
• Close the channel
• Encapsulate 1.-3. and expose them via a
reader channel
CS3211 L7 - Concurrency in Go 43
Ownership increases safety
• Because we’re the one initializing the channel, we remove the risk of
deadlocking by writing to a nil channel
• Because we’re the one initializing the channel, we remove the risk of
panicking by closing a nil channel
• Because we’re the one who decides when the channel gets closed,
we remove the risk of panicking by writing to a closed channel
• Because we’re the one who decides when the channel gets closed,
we remove the risk of panicking by closing a channel more than once
• We wield the type checker at compile time to prevent improper
writes to our channel

CS3211 L7 - Concurrency in Go 44
select statement
• Compose channels together in a program to form larger abstractions
• Bind together channels
• locally, within a single function or type,
• globally, at the intersection of two or more components in a system
• Help safely bring channels together with concepts like cancellations,
timeouts, waiting, and default values
• Similar in syntax with a switch block
• BUT case statements aren’t tested sequentially, and execution won’t
automatically fall through if none of the criteria are met

CS3211 L7 - Concurrency in Go 45
Behavior of select
• All channel reads and writes (case statements) are considered
simultaneously to see if any of them are ready
• populated or closed channels in the case of reads
• channels that are not at capacity in the case of writes
• The entire select statement blocks if none of the channels are ready
• Handle the following:
• Multiple channels have something to read
• There are never any channels that become ready
• We want to do something, but no channels are currently ready

CS3211 L7 - Concurrency in Go 46
Multiple channels have something to read

• Output:
c1Count: 505
c2Count: 496
• Go runtime will perform a pseudorandom uniform selection over the set of case
statements
• Each case has an equal chance of being selected

CS3211 L7 - Concurrency in Go 47
Channels are not ready
• Never ready: timeout
• Line 44: time.After returns a channel that sends the current time after a
time.Duration
• Do work while waiting: use default

CS3211 L7 - Concurrency in Go 48
For-select loop

• Allows a goroutine to make


progress on work while
waiting for another goroutine
to report a result

CS3211 L7 - Concurrency in Go 49
The sync package
Regarding mutexes, the sync package implements them, but we hope
Go programming style will encourage people to try higher-level
techniques. In particular, consider structuring your program so that
only one goroutine at a time is ever responsible for a particular piece of
data.
Do not communicate by sharing memory.
Instead, share memory by communicating.

CS3211 L7 - Concurrency in Go 50
Sync package
• Used mostly in small scopes such as a
struct
• Contains
• WaitGroup: wait for a set of concurrent
operations to complete
• Synchronization primitives
• Mutex and RWMutex
• Cond
• Once
• Basic constructs
• Pool

CS3211 L7 - Concurrency in Go 51
The Go memory model
• Specifies the conditions under which reads of a variable in one
goroutine can be guaranteed to observe values produced by writes to
the same variable in a different goroutine
• Happens Before
• Synchronization of goroutines and channels

CS3211 L7 - Concurrency in Go 52
Happens before
• Within a single goroutine, reads and writes must behave as if they
executed in the order specified by the program (sequenced before)
• The execution order observed by one goroutine may differ from the
order perceived by another
• To guarantee that a read r of a variable v observes a particular write w
to v, ensure that w is the only write r is allowed to observe. That is, r
is guaranteed to observe w if both of the following hold:
• w happens before r.
• Any other write to the shared variable v either happens before w or after r.
• The happens before relation is defined as the transitive closure of the
union of the sequenced before and synchronized before relations.

CS3211 L7 - Concurrency in Go 53
Synchronized before
• The go statement that starts a new goroutine synchronized before
the goroutine's execution begins
• The exit of a goroutine is not guaranteed to be synchronized before
any event in the program
• A send on a channel is synchronized before the completion of the
corresponding receive from that channel.
• The closing of a channel is synchronized before a receive that returns
a zero value because the channel is closed
• A receive from an unbuffered channel is synchronized before the
completion of the corresponding send on that channel.
• The kth receive on a channel with capacity C is synchronized before
the (k+C)th send from that channel completes.
CS3211 L7 - Concurrency in Go 54
Send-receive Synchronized Before
• A send on a channel is synchronized before the
completion of the corresponding receive from that
channel.

• A receive from an unbuffered channel is synchronized


before the completion of the corresponding send on
that channel.

CS3211 L7 - Concurrency in Go 55
Summary
• Go helps distinguish between concurrency and parallelism
• Using a different way to implement concurrency based on CSP
• Goroutines and channels

References
• “Concurrency in Go” by Katherine Cox-Buday, 2017.
• “Concurrency is not Parallelism” by Rob Pike
• https://go.dev/ref/mem

CS3211 L7 - Concurrency in Go 56

You might also like