The Go Programming Language. Part 3

Similar documents
Distributed Systems. 02r. Go Programming. Paul Krzyzanowski. TA: Yuanzhen Gu. Rutgers University. Fall 2015

go get my/vulnerabilities Green threads are not eco friendly threads

The Go Programming Language. Frank Roberts

Go Forth and Code. Jonathan Gertig. CSC 415: Programing Languages. Dr. Lyle

CSE 153 Design of Operating Systems Fall 2018

GO CONCURRENCY BASICS AND PATTERNS EXPLAINED IN COLOR

05-concurrency.txt Tue Sep 11 10:05: , Fall 2012, Class 05, Sept. 11, 2012 Randal E. Bryant

CS 153 Design of Operating Systems Winter 2016

Introduzione a Go e RPC in Go

Thrift specification - Remote Procedure Call

Go Cheat Sheet. Operators. Go in a Nutshell. Declarations. Basic Syntax. Hello World. Functions. Comparison. Arithmetic. Credits

func findbestfold(seq string, energyfunction func(fold)float64)) Fold {

CSE 153 Design of Operating Systems

CS 326: Operating Systems. Process Execution. Lecture 5

Concurrency, Thread. Dongkun Shin, SKKU

Summary: Open Questions:

Threading and Synchronization. Fahd Albinali

CS 5523 Operating Systems: Midterm II - reivew Instructor: Dr. Tongping Liu Department Computer Science The University of Texas at San Antonio

Operating Systems. Operating Systems Summer 2017 Sina Meraji U of T

Go for Java Developers

Threads and Continuations COS 320, David Walker

Go Tutorial. To do. A brief, gentle intro to Go. Next Networking. q Today

RPC and Threads. Jinyang Li. These slides are based on lecture notes of 6.824

CSE 120 Principles of Operating Systems

understanding

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Concurrent Server Design Multiple- vs. Single-Thread

Go Concurrent Programming. QCon2018 Beijing

GO SHORT INTERVIEW QUESTIONS EXPLAINED IN COLOR

Chapter 4: Threads. Operating System Concepts 9 th Edit9on

6.001 Notes: Section 17.5

CS 261 Fall Mike Lam, Professor. Threads

Concurrent ML. John Reppy January 21, University of Chicago

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring 2004

Operating Systems. Synchronization

What the CPU Sees Basic Flow Control Conditional Flow Control Structured Flow Control Functions and Scope. C Flow Control.

10/17/ Gribble, Lazowska, Levy, Zahorjan 2. 10/17/ Gribble, Lazowska, Levy, Zahorjan 4

Threads. Raju Pandey Department of Computer Sciences University of California, Davis Spring 2011

You can also launch the instances on different machines by supplying IPv4 addresses and port numbers in the format :3410

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring 2002

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

Deadlock and Monitors. CS439: Principles of Computer Systems September 24, 2018

Concurrency & Parallelism. Threads, Concurrency, and Parallelism. Multicore Processors 11/7/17

Static Deadlock Detection for Go by Global Session Graph Synthesis. Nicholas Ng & Nobuko Yoshida Department of Computing Imperial College London

I/O Management Software. Chapter 5

CS11 Java. Fall Lecture 7

Threads, Concurrency, and Parallelism

Erlang and Go (CS262a, Berkeley Fall 2016) Philipp Moritz

Last class: Today: Thread Background. Thread Systems

What Came First? The Ordering of Events in

CS510 Advanced Topics in Concurrency. Jonathan Walpole

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Steve Gribble. Synchronization. Threads cooperate in multithreaded programs

The New Java Technology Memory Model

Synchronization. CS61, Lecture 18. Prof. Stephen Chong November 3, 2011

Network Communication and Remote Procedure Calls

Chapter 6: Process Synchronization

ECE 650 Systems Programming & Engineering. Spring 2018

CS 241 Honors Concurrent Data Structures

Threads. Threads The Thread Model (1) CSCE 351: Operating System Kernels Witawas Srisa-an Chapter 4-5

Formal Methods of Software Design, Eric Hehner, segment 1 page 1 out of 5

Operating Systems 2 nd semester 2016/2017. Chapter 4: Threads

Introduction to pthreads

Operating Systems (234123) Spring (Homework 3 Wet) Homework 3 Wet

Go Language September 2016

Questions answered in this lecture: CS 537 Lecture 19 Threads and Cooperation. What s in a process? Organizing a Process

! Design constraints. " Component failures are the norm. " Files are huge by traditional standards. ! POSIX-like

CS-537: Midterm Exam (Fall 2013) Professor McFlub

CSE 120 Principles of Operating Systems

I/O Management Software. Chapter 5

!! How is a thread different from a process? !! Why are threads useful? !! How can POSIX threads be useful?

Last 2 Classes: Introduction to Operating Systems & C++ tutorial. Today: OS and Computer Architecture

Last Class: CPU Scheduling. Pre-emptive versus non-preemptive schedulers Goals for Scheduling: CS377: Operating Systems.

CS 6112 (Fall 2011) Foundations of Concurrency

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

Pebbles Kernel Specification September 26, 2004

Suggested Solutions (Midterm Exam October 27, 2005)

Google GO. An introduction. Paolo Baldan Linguaggi per il Global Computing AA 2017/2018

pthreads CS449 Fall 2017

CS 450 Operating System Week 4 Lecture Notes

Problems with Concurrency. February 19, 2014

What did we talk about last time? Course overview Policies Schedule

Multiprocessors II: CC-NUMA DSM. CC-NUMA for Large Systems

Multithreaded Programming

MultiThreading 07/01/2013. Session objectives. Introduction. Introduction. Advanced Java Programming Course

Computation Abstractions. Processes vs. Threads. So, What Is a Thread? CMSC 433 Programming Language Technologies and Paradigms Spring 2007

Safety and liveness for critical sections

An Introduction to Erlang

Advanced Java Programming Course. MultiThreading. By Võ Văn Hải Faculty of Information Technologies Industrial University of Ho Chi Minh City

Protocols SPL/ SPL

SPIN, PETERSON AND BAKERY LOCKS

Go Programming. Russ Cox and Rob Pike May 20, 2010

Starting to Program in C++ (Basics & I/O)

Non-blocking Array-based Algorithms for Stacks and Queues. Niloufar Shafiei

CSE 451: Operating Systems Winter Lecture 7 Synchronization. Hank Levy 412 Sieg Hall

MITOCW watch?v=w_-sx4vr53m

JAVA CONCURRENCY FRAMEWORK. Kaushik Kanetkar

Learning from Bad Examples. CSCI 5828: Foundations of Software Engineering Lecture 25 11/18/2014

Shared Variables and Interference

Control Abstraction. Hwansoo Han

Threads. CS3026 Operating Systems Lecture 06

Transcription:

The Go Programming Language Part 3 Rob Pike r@google.com (updated June 2011) 1

Today s Outline Exercise any questions? Concurrency and communication goroutines channels concurrency issues 2

Exercise Any questions? For a trivial HTTP server with various generators, see http://golang.org/src/pkg/http/triv.go 3

Concurrency and communication: Goroutines 4

Goroutines Terminology: There are many terms for "things that run concurrently" - process, thread, coroutine, POSIX thread, NPTL thread, lightweight process,..., but these all mean slightly different things. None means exactly how Go does concurrency. So we introduce a new term: goroutine. 5

Definition A goroutine is a Go function or method executing concurrently in the same address space as other goroutines. A running program consists of one or more goroutines. It's not the same as a thread, coroutine, process, etc. It's a goroutine. Note: Concurrency and parallelism are different concepts. Look them up if you don't understand the difference. There are many concurrency questions. They will be addressed later; for now just assume it all works as advertised. 6

Starting a goroutine Invoke a function or method and say go: func IsReady(what string, minutes int64) { time.sleep(minutes * 60*1e9) // Unit is nanosecs. fmt.println(what, "is ready") go IsReady("tea", 6) go IsReady("coffee", 2) fmt.println("i'm waiting...") Prints: I'm waiting... (right away) coffee is ready (2 minutes later) tea is ready (6 minutes later) 7

Some simple facts Goroutines are cheap. Goroutines exit by returning from their top-level function, or just falling off the end. Goroutines can run concurrently on different processors, sharing memory. You don't have to worry about stack size. 8

Stacks In gccgo, at least for now, goroutines are pthreads. In 6g they're multiplexed onto threads, so they are much cheaper. In both worlds, stacks are small (a few kb) and grow as needed. Thus goroutines use little memory, you can have lots of them, and they can dynamically have huge stacks. The programmer shouldn't have to think about the stack size issue, and in Go, it doesn't even come up. 9

Scheduling Goroutines are multiplexed as needed onto system threads. When a goroutine executes a blocking system call, no other goroutine is blocked. Plan to do the same for CPU-bound goroutines at some point, but for now, if you want userlevel parallelism in 6g * you must set shell var. GOMAXPROCS or call runtime.gomaxprocs(n). GOMAXPROCS tells the runtime scheduler how many user-space-executing goroutines to run at once, ideally on different CPU cores. * gccgo always uses one thread per goroutine. 10

Concurrency and communication: Channels 11

Channels in Go Unless two goroutines can communicate, they can't coordinate. Go has a type called a channel that provides communication and synchronization capabilities. It also has special control structures that build on channels to make concurrent programming easy. Note: I gave a talk in 2006 about predecessor stuff in an older language. http://www.youtube.com/watch?v=hmxncea8ctw 12

The channel type In its simplest form the type looks like this: chan elementtype With a value of this type, you can send and receive items of elementtype. Channels are a reference type, which means if you assign one chan variable to another, both variables access the same channel. It also means you use make to allocate one: var c = make(chan int) 13

The communication operator: <- The arrow points in the direction of data flow. As a binary operator, <- sends the value on the right to the channel on the left: c := make(chan int) c <- 1 // send 1 on c (flowing into c) As a prefix unary operator, <- receives from a channel: v = <-c // receive value from c, assign to v <-c // receive value, throw it away i := <-c // receive value, initialize i 14

Semantics By default, communication is synchronous. (We'll talk about asynchronous communication later.) This means: 1) A send operation on a channel blocks until a receiver is available for the same channel. 2) A receive operation for a channel blocks until a sender is available for the same channel. Communication is therefore a form of synchronization: two goroutines exchanging data through a channel synchronize at the moment of communication. 15

Let's pump some data func pump(ch chan int) { for i := 0; ; i++ { ch <- i ch1 := make(chan int) go pump(ch1) // pump hangs; we run fmt.println(<-ch1) // prints 0 Now we start a looping receiver. func suck(ch chan int) { for { fmt.println(<-ch) go suck(ch1) // tons of numbers appear You can still sneak in and grab a value: fmt.println(<-ch1) // Prints 314159 16

Functions returning channels In the previous example, pump was like a generator spewing out values. But there was a lot of fuss allocating channels etc. Let's package it up into a function returning the channel of values. func pump() chan int { ch := make(chan int) go func() { for i := 0; ; i++ { ch <- i () return ch stream := pump() fmt.println(<-stream) // prints 0 "Function returning channel" is an important idiom. 17

Channel functions everywhere I am avoiding repeating famous examples you can find elsewhere. Here are a couple to look up: 1) The prime sieve; in the language specification and also in the tutorial. 2) Doug McIlroy's power series paper: http://plan9.bell-labs.com/who/rsc/thread/squint.pdf A Go version of this amazing program is in available in the test suite as: http://golang.org/test/chan/powser1.go 18

Range and channels The range clause on for loops accepts a channel as an operand, in which case the for loops over the values received from the channel. We rewrote pump; here's the rewrite for suck, making it launch the goroutine as well: func suck(ch chan int) { go func() { for v := range ch { fmt.println(v) () suck(pump()) // doesn't block now 19

Closing a channel How does range know when the channel is done delivering data? The sender calls the built-in function close: close(ch) Receiver tests if the sender has closed the channel using "comma ok": val, ok := <-ch Result is (value, true) while values are available; once channel is closed and drained, result is (zero, false). 20

Range on a channel, by hand A for range on a channel such as: for value := range <-ch { use(value) is equivalent to: for { value, ok := <-ch if!ok { break use(value) 21

Close Key points: Only the sender should call close. Only the receiver can ask if channel has been closed. Can only ask while getting a value (avoids races). Call close only when it's necessary to signal to the receiver that no more values will arrive. Most of the time, close isn't needed; it's not analogous to closing a file. Channels are garbage-collected regardless. 22

Channel directionality In its simplest form a channel variable is an unbuffered (synchronous) value that can be used to send and receive. A channel type may be annotated to specify that it may only send or only receive: var recvonly <-chan int var sendonly chan<- int 23

Channel directionality (II) All channels are created bidirectional, but we can assign them to directional channel variables. Useful for instance in functions, for (type) safety: func sink(ch <-chan int) { for { <-ch func source(ch chan<- int) { for { ch <- 1 c := make(chan int) // bidirectional go source(c) go sink(c) 24

Synchronous channels Synchronous channels are unbuffered. Sends do not complete until a receiver has accepted the value. c := make(chan int) go func() { time.sleep(60*1e9) x := <-c fmt.println("received", x) () fmt.println("sending", 10) c <- 10 fmt.println("sent", 10) Output: sending 10 (happens immediately) sent 10 (60s later, these 2 lines appear) received 10 25

Asynchronous channels A buffered, asynchronous channel is created by telling make the number of elements in the buffer. c := make(chan int, 50) go func() { time.sleep(60*1e9) x := <-c fmt.println("received", x) () fmt.println("sending", 10) c <- 10 fmt.println("sent", 10) Output: sending 10 (happens immediately) sent 10 (now) received 10 (60s later) 26

Buffer is not part of the type Note that the buffer's size, or even its existence, is not part of the channel's type, only of the value. This code is therefore legal, although dangerous: buf = make(chan int, 1) unbuf = make(chan int) buf = unbuf unbuf = buf Buffering is a property of the value, not of the type. 27

Select Select is a control structure in Go analogous to a communications switch statement. Each case must be a communication, either send or receive. ci, cs := make(chan int), make(chan string) select { case v := <-ci: fmt.printf("received %d from ci\n", v) case v := <-cs: fmt.printf("received %s from cs\n", v) Select executes one runnable case at random. If no case is runnable, it blocks until one is. A default clause is always runnable. 28

Select semantics Quick summary: - Every case must be a (possibly :=) communication - All channel expressions are evaluated - All expressions to be sent are evaluated - If any communication can proceed, it does; others are ignored - If multiple cases are ready, one is selected at random, fairly. Others do not execute. - Otherwise: - If there is a default clause, that runs - If there is no default, select statement blocks until one communication can proceed; there is no re-evaluation of channels or values 29

Random bit generator Silly but illustrative example. c := make(chan int) go func() { for { fmt.println(<-c) () for { select { case c <- 0: // no statement, no fall through case c <- 1: Prints 0 1 1 0 0 1 1 1 0 1... 30

Testing for communicability Can a communication proceed without blocking? Select with a default clause can tell us: select { case v := <-ch: fmt.println("received", v) default: fmt.println("ch not ready for receive") The default clause executes if no other case can proceed, so this is the idiom for non-blocking receive; non-blocking send is the obvious variant. 31

Timeout Can a communication succeed in a given interval? Package time contains the After function: func After(ns int64) <-chan int64 It delivers a value (the current time) on the returned channel after the specified interval. Use it in select to implement timeout: select { case v := <-ch: fmt.println("received", v) case <-time.after(30*1e9): fmt.println("timed out after 30 seconds") 32

Multiplexing Channels are first-class values, which means they can be sent over channels. This property makes it easy to write a service multiplexer since the client can supply, along with its request, the channel on which to reply. chanofchans := make(chan chan int) Or more typically type Reply struct {... type Request struct { arg1, arg2 sometype replyc chan *Reply 33

Multiplexing server type request struct { a, b int replyc chan int type binop func(a, b int) int func run(op binop, req *request) { req.replyc <- op(req.a, req.b) func server(op binop, service <-chan *request) { for { req := <-service // requests arrive here go run(op, req) // don't wait for op 34

Starting the server Use the "function returning channel" idiom to create a channel to a new server: func startserver(op binop) chan<- *request { service := make(chan *request) go server(op, req) return service adderchan := startserver( func(a, b int) int { return a + b ) 35

The client A similar example is worked in more detail in the tutorial, but here's a variant: func (r *request) String() string { return fmt.sprintf("%d+%d=%d", r.a, r.b, <-r.replyc) req1 := &request{7, 8, make(chan int) req2 := &request{17, 18, make(chan int) Requests are ready; send them: adderchan <- req1 adderchan <- req2 Can retrieve results in any order; r.replyc demuxes: fmt.println(req2, req1) 36

Teardown In the multiplex example, the server runs forever. To tear it down cleanly, signal with a channel. This server has the same functionality but with a quit channel: func server(op binop, service <-chan *request, quit <-chan bool) { for { select { case req := <-service: go run(op, req) // don't wait for it case <-quit: return 37

Starting the server The rest of the code is mostly the same, with an extra channel: func startserver(op binop) (service chan<- *request, quit chan<- bool) { service = make(chan *request) quit = make(chan bool) go server(op, service, quit) return service, quit adderchan, quitchan := startserver( func(a, b int) int { return a + b ) 38

Teardown: the client The client is unaffected until it's ready to shut down the server: req1 := &request{7, 8, make(chan int) req2 := &request{17, 18, make(chan int) adderchan <- req1 adderchan <- req2 fmt.println(req2, req1) All done, signal server to exit: quitchan <- true 39

Chaining package main import ("flag"; "fmt") var ngoroutine = flag.int("n", 100000, "how many") func f(left, right chan int) { left <- 1 + <-right func main() { flag.parse() leftmost := make(chan int) var left, right chan int = nil, leftmost for i := 0; i < *ngoroutine; i++ { left, right = right, make(chan int) go f(left, right) right <- 0 // bang! x := <-leftmost // wait for completion fmt.println(x) // 100000 40

Example: Channel as Buffer cache var freelist = make(chan *Buffer, 100) var serverchan = make(chan *Buffer) func server() { for { b := <-serverchan // Wait for work to do. process(b) // Process the request in buffer. select { case freelist <- b: // Reuse buffer if room. default: // Otherwise drop it. func client() { for { var b *Buffer select { case b = <-freelist: default: b = new(buffer) // Allocate if not. // Grab one if available. load(b) // Read next request into b. serverchan <- b // Send request to server. 41

Concurrency 42

Concurrency issues Many issues, of course, but Go tries to take care of them. Channel send and receive are atomic. The select statement is very carefully defined and implemented, etc. But goroutines run in shared memory, communication networks can deadlock, multithreaded debuggers suck, and so on. What to do? 43

Go gives you the primitives Don't program the way you would in C or C++ or even Java. Channels give you synchronization and communication both, and that makes them powerful but also easy to reason about if you use them well. The rule is: Do not communicate by sharing memory. Instead, share memory by communicating. The very act of communication guarantees synchronization! 44

The model For instance, use a channel to send data to a dedicated server goroutine. If only one goroutine at a time has a pointer to the data, there are no concurrency issues. This is the model we advocate for programming servers, at least. It's the old "one thread per client" approach, generalized - and in use since the 1980s. It works very well. My old talk (mentioned above) goes into this idea in more depth. 45

The memory model The nasty details about synchronization and shared memory are written down at: http://golang.org/doc/go_mem.html But you rarely need to understand them if you follow our approach. 46

The Go Programming Language Part 3 Rob Pike r@google.com (updated June 2011) 47