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

Similar documents
The Go Programming Language. Frank Roberts

CS558 Programming Languages

6.001 Notes: Section 15.1

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

So on the survey, someone mentioned they wanted to work on heaps, and someone else mentioned they wanted to work on balanced binary search trees.

CS558 Programming Languages

CS558 Programming Languages

developed ~2007 by Robert Griesemer, Rob Pike, Ken Thompson open source

Operating Systems. 18. Remote Procedure Calls. Paul Krzyzanowski. Rutgers University. Spring /20/ Paul Krzyzanowski

CSE351 Winter 2016, Final Examination March 16, 2016

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #2 Examination 12:30 noon, Thursday, March 15, 2012

Project Compiler. CS031 TA Help Session November 28, 2011

Motivations History Principles Language Gommunity Success stories Conclusion. Let s Go! A brief introduction to Google s new language.

Programming overview

GO SHORT INTERVIEW QUESTIONS EXPLAINED IN COLOR

Notes on the Exam. Question 1. Today. Comp 104:Operating Systems Concepts 11/05/2015. Revision Lectures (separate questions and answers)

Week 7. Statically-typed OO languages: C++ Closer look at subtyping

Go for Java Developers

GO CONCURRENCY BASICS AND PATTERNS EXPLAINED IN COLOR

Comp 204: Computer Systems and Their Implementation. Lecture 25a: Revision Lectures (separate questions and answers)

CHAPTER 3 - PROCESS CONCEPT

How we use Go to build APIs PubNative best practices and patterns. Kostiantyn Stepaniuk PubNative GmbH

Building custom components IAT351

Slide 1 CS 170 Java Programming 1 The Switch Duration: 00:00:46 Advance mode: Auto

Lecture 05 I/O statements Printf, Scanf Simple statements, Compound statements

Day 6. COMP1006/1406 Summer M. Jason Hinek Carleton University

Outline for Today. Why could we construct them in time O(n)? Analyzing data structures over the long term.

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

CSci Introduction to Distributed Systems. Communication: RPC

Distributed Systems 8. Remote Procedure Calls

PROFESSOR: Well, now that we've given you some power to make independent local state and to model objects,

Another Go at Language Design

Type Systems, Type Inference, and Polymorphism

Question 1. Notes on the Exam. Today. Comp 104: Operating Systems Concepts 11/05/2015. Revision Lectures

PROFESSOR: Last time, we took a look at an explicit control evaluator for Lisp, and that bridged the gap between

OOP Design Conclusions and Variations

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

OCaml Data CMSC 330: Organization of Programming Languages. User Defined Types. Variation: Shapes in Java

CORE JAVA TRAINING COURSE CONTENT

Go on NetBSD (and pkgsrc!) A modern systems programming language 23 March Benny Siegert Google Switzerland; The NetBSD Foundation

Inheritance, Polymorphism and the Object Memory Model

Summary. Recursion. Overall Assignment Description. Part 1: Recursively Searching Files and Directories

Protocol Buffers, grpc

CS 237 Meeting 19 10/24/12

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

Distributed Systems. How do regular procedure calls work in programming languages? Problems with sockets RPC. Regular procedure calls

Programming Languages and Techniques (CIS120)


Introduction to Programming Using Java (98-388)

CHAPTER - 4 REMOTE COMMUNICATION

Remote Procedure Call

Agenda Time (PT) 8:45 a.m. Event Platform Opening 9:00 a.m. Keynote - Java: Present and Future Java EE 7 Java SE 8 Java Embedded

Threads and Continuations COS 320, David Walker

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

Operational Semantics. One-Slide Summary. Lecture Outline

Distributed Systems Theory 4. Remote Procedure Call. October 17, 2008

Introduzione a Go e RPC in Go

Supporting Class / C++ Lecture Notes


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

Types II. Hwansoo Han

CSCI-1680 RPC and Data Representation. Rodrigo Fonseca

Postfix (and prefix) notation

CS2110 Assignment 3 Inheritance and Trees, Summer 2008

CSCI-1680 RPC and Data Representation John Jannotti

Data Types The ML Type System

Processes and Threads

printf( Please enter another number: ); scanf( %d, &num2);

Super-Classes and sub-classes

CS 2112 Lecture 20 Synchronization 5 April 2012 Lecturer: Andrew Myers

6.S096 Lecture 10 Course Recap, Interviews, Advanced Topics

Part Two - Process Management. Chapter 3: Processes

CS02b Project 2 String compression with Huffman trees

OPERATING SYSTEM. Chapter 4: Threads

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Priority Queues / Heaps Date: 9/27/17

In Java we have the keyword null, which is the value of an uninitialized reference type

Garbage Collection (1)

Introduction to pthreads

CIT Week13 Lecture

These are notes for the third lecture; if statements and loops.

Lessons learnt building Kubernetes controllers. David Cheney - Heptio

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

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

1 Shyam sir JAVA Notes

Week - 04 Lecture - 01 Merge Sort. (Refer Slide Time: 00:02)

Chapter 4 Communication

Chapter 11. Categories of languages that support OOP: 1. OOP support is added to an existing language

The Procedure Abstraction

Tasks of the Tokenizer

(Refer Slide Time: 00:51)

6.001 Notes: Section 8.1

Data structures. Priority queues, binary heaps. Dr. Alex Gerdes DIT961 - VT 2018

A Third Look At Java. Chapter Seventeen Modern Programming Languages, 2nd ed. 1

Java Primer 1: Types, Classes and Operators

SERIOUS ABOUT SOFTWARE. Qt Core features. Timo Strömmer, May 26,

Process. Operating Systems (Fall/Winter 2018) Yajin Zhou ( Zhejiang University

Piqi-RPC. Exposing Erlang services via JSON, XML and Google Protocol Buffers over HTTP. Friday, March 25, 2011

Administrivia. Remote Procedure Calls. Reminder about last time. Building up to today

Concurrency in Go 9/22/17

1 Getting used to Python

Transcription:

Go Programming Russ Cox and Rob Pike May 20, 2010

Live waving View live notes and ask questions about this session on Google Wave: http://bit.ly/go2010io 3

Go is different Go is more unusual than you might first think. Programming in Go is different from programming in most procedural languages. If you try to write Java* programs in Go, you may become frustrated. If you write Go programs in Go, you will be much more productive. Our goal today is to teach you to think like a Go programmer. *Sometimes we'll use Java as a reference for comparison but we could make the same points comparing Go to a number of other languages. 4

Go is and Go is not Go is object-oriented not type-oriented inheritance is not primary methods on any type, but no classes or subclasses Go is (mostly) implicit not explicit types are inferred not declared objects have interfaces but they are derived, not specified Go is concurrent not parallel intended for program structure, not maximum performance but still can keep all the cores humming nicely... and some programs are nicer even if not parallel at all 5

1: Evaluating expressions

A specification of behavior Expression evaluators often define a type, called Value, as a parent class with integers, strings, etc. as child classes. In Go, we just specify what a Value needs to do. For our simple example, that means: do binary operations and be printable. type Value interface { BinaryOp(op string, y Value) Value String() string Implement those methods and you have a type that the evaluator can use. 7

Integer values Dead easy; just write the methods. (No extra bookkeeping.) type Int int // A basic type (not a pointer, struct, or class). func (x Int) String() string { return strconv.itoa(int(x)) func (x Int) BinaryOp(op string, y Value) Value { switch y := y.(type) { case Int: switch op { case "+": return x + y case "-": return x - y case "*": return x * y... case Error: // defined on the next slide return y return Error(fmt.Sprintf("illegal op: '%v %s %v'", x, op, y)) 8

Errors For error handling, define an Error type that satisfies Value that will just propagate the error up the evaluation tree. type Error string func (e Error) String() string { return string(e) func (e Error) BinaryOp(op string, y Value) Value { return e No need for "implements" clauses or other annotations. Ints and Errors are Values because they satisfy the Value interface implicitly. 9

Input We need a basic scanner to input values. Here's a simple one that, given a string, returns a Value representing an integer or error. func newval(lit string) Value { x, err := strconv.atoi(lit) if err == nil { return Int(x) return Error(fmt.Sprintf("illegal literal '%s'", lit)) The evaluator just tokenizes, parses and, in effect, calls fmt.println(newval("2").binaryop("+", newval("4")).string()) 10

Demo

Let's add strings type String string func (x String) String() string { return strconv.quote(string(x)) func (x String) BinaryOp(op string, y Value) Value { switch y := y.(type) { case String: switch op { case "+": return x + y... case Int: // String * Int switch op { case "*": return String(strings.Repeat(string(x), int(y)))... case Error: return y return Error(fmt.Sprintf("illegal op: '%v %s %v'", x, op, y)) 12

String input Just a few more lines in newval. func newval(lit string) Value { x, err := strconv.atoi(lit) if err == nil { return Int(x) s, err := strconv.unquote(lit) if err == nil { return String(s) return Error(fmt.Sprintf("illegal literal '%s'", lit)) We've added strings by just adding strings. This happens because of Go's implicit interface satisfaction. No retroactive bookkeeping. 13

Demo

Objects but no hierarchy In Java, the type hierarchy is the foundation of the program, which can be hard to change as the design evolves. (Can be easier to compromise the design than change the foundation.) Programming in Go is not primarily about types and inheritance. There is no type hierarchy. The most important design decisions don't have to be made first, and it's easy to change types as the program develops because the compiler infers their relationships automatically. Go programs are therefore more flexible and adaptable. 15

2: Not inheritance

Java: Compressing using Buffers, given byte[] (1) Suppose we have a zlib compressor: public static class ZlibCompressor { public int compress(byte[] in, int inoffset, int inlength, byte[] out, int outoffset) {...... and we want to support Buffer in a way that will generalize to other compressors. 17

Java: Compressing using Buffers, given byte[] (2) Define an abstract compressor class. public abstract class AbstractCompressor { /** Compresses the input into the output buffer. */ abstract int compress(byte[] in, int inoffset, int inlength, byte[] out, int outoffset); /** * Compresses byte buffers using abstract compress method. * Assumes Buffers are based on arrays. */ public void compress(buffer in, Buffer out) { int numwritten = compress(in.array(), in.arrayoffset() + in.position(), in.remaining(), out.array(), out.arrayoffset() + out.position()); out.position(out.position() + numwritten); 18

Java: Compressing using Buffers, given byte[] (3) Subclass the abstract class to create a compression class. public static class ZLibCompressor extends AbstractCompressor { public int compress(byte[] in, int inoffset, int inlength, byte[] out, int outoffset) {... This is common Java style: Inherit the abstract behavior. 19

Go: Compressing using Buffers, given []byte (1) Again, we have a zlib compressor: type ZlibCompressor struct {... func (c *ZlibCompressor) Compress(in, out []byte) int Again, we want to support Buffer in a way that will generalize to other compressors. 20

Go: Compressing using Buffers, given []byte (2) Define an interface for the compressor and write a function. type Compressor interface { Compress(in, out []byte) int func CompressBuffer(c Compressor, in, out *Buffer) { n := c.compress(in.bytes(), out.bytes()) out.advance(n) This is good Go style: just use the abstract behavior. It's easy and much less typing (in two senses). You can use this approach in Java but it's not usual Java style. Java (like many languages) puts type inheritance first. 21

Implicitness means flexibility In Go, could use as many wrappers as you like. A type can satisfy many interfaces and therefore be used by any number of 'abstract wrappers' like CompressBuffer. In Java, can only extend one abstract class. Could use Java interfaces but still need to annotate the original implementation that is, edit the existing code. What if it's not yours to edit? In Go, Compressor's implementers do not need to know about CompressBuffer or even the Compressor interface. The Buffer type might be private yet the type with the Compress method could be in a standard library. 22

3: Lightweight interfaces

Interfaces are lightweight A typical Go interface has only one or two methods. (In fact, the commonest interface has zero, but that's another story.) Programmers new to Go see interfaces as a building block for type hierarchies and tend to create interfaces with many methods. But that's the wrong way to think about them. They are: small nimble often ad hoc 24

Problem: Generalizing RPC The RPC package in Go uses package gob to marshal objects on the wire. We needed a variant that used JSON. Abstract the codec into an interface: type ServerCodec interface { ReadRequestHeader(*Request) os.error ReadRequestBody(interface{) os.error WriteResponse(*Response, interface{) os.error Close() os.error 25

Problem: Generalizing RPC Two functions must change signature: func sendresponse(sending *sync.mutex, req *Request, reply interface{, enc *gob.encoder, errmsg string) becomes func sendresponse(sending *sync.mutex, req *Request, reply interface{, enc ServerCodec, errmsg string) And similarly for requests. That is almost the whole change to the RPC implementation. The bodies of the functions needed a couple of tiny edits. In other such examples, often no editing would be required. 26 We saw an opportunity: RPC needed only Read and Write methods. Put those in an interface and you've got abstraction. Post facto.

Total time: 20 minutes And that includes writing and testing the JSON implementation of the interface. (We wrote a trivial gobservercodec type to implement the new rpc.servercodec interface.) In Java, RPC would be refactored into a half-abstract class, subclassed to create JsonRPC and GobRPC. In Go, there is no need to manage a type hierarchy: just pass in a codec interface stub (and nothing else). 27

4: Common interfaces

Post facto abstraction In the previous example, we were in charge of all the pieces. But it's common for interfaces to arise as codifications of existing patterns. Such interfaces often include only one or two methods: io.reader, io.writer, etc. It is vital that such interfaces do not need retrofitting to work with existing code. They work automatically. 29

Simple interfaces are widely used The type aes.cipher has methods: func (c *Cipher) BlockSize() int // size of encryption unit func (c *Cipher) Decrypt(src, dst []byte) // decrypt one block func (c *Cipher) Encrypt(src, dst []byte) // encrypt one block So do blowfish.cipher, xtea.cipher and others. We can make ciphers interchangeable by defining an interface: type Cipher interface { BlockSize() int Decrypt(src, dst []byte) Encrypt(src, dst []byte) 30

Chaining ciphers We define block cipher modes using the interface. // cipher-block chaining func NewCBCDecrypter(c Cipher, iv []byte, r io.reader) io.reader // cipher feedback func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.reader) io.reader // output feedback func NewOFBReader(c Cipher, iv []byte, r io.reader) io.reader Want AES CBC mode? // (For brevity, we cheat a bit here about error handling) r = block.newcbcdecrypter(aes.newcipher(key), iv, r) Blowfish CBC? r = block.newcbcdecrypter(blowfish.newcipher(key), iv, r) No need for multiple CBC implementations. 31

Chain away Libraries in other languages usually provide an API with the cross product of all useful ciphers and chainers. Go just needs to provide the building blocks. And more! Decrypt and decompress by chaining further. func DecryptAndGunzip(dstfile, srcfile string, key, iv []byte) { f := os.open(srcfile, os.o_rdonly, 0) // open source file defer f.close() c := aes.newcipher(key) // create cipher r := block.newofbreader(c, iv, f) // decrypting reader r = gzip.newreader(r) // decompressing reader w := os.open(dstfile, os.o_wronly os.o_create, 0666) defer w.close() io.copy(w, r) // copy to output (Again, cheating a bit regarding error handling.) 32

5: Concurrency for structure

Concurrent programs Java programmers use class hierarchies to structure their programs. Go's concurrency primitives provide the elements of another approach. It's not about parallelism. Concurrent programming allows parallelism but that's not what it's really for. It's about expressing program structure to represent independently executing actions. In short: - parallelism is about performance - concurrency is about program design 34

Example: a load balancer Imagine you have many processes requesting actions and a few workers that share the load. Assume workers are more efficient if they batch many requests. We want a load balancer that distributes the load fairly across the workers according to their current workload. In real life we'd distribute work across many machines, but for simplicity we'll just focus on a local load balancer. This is simplistic but representative of the core of a realistic problem. 35

Life of a request Requesters make a request to the load balancer. Load balancer immediately sends the request to the most lightly loaded worker. When it completes the task the worker replies directly to the requester. Balancer adjusts its measure of the workloads. 36

A load balancer Requester Requester Requester Requester... many more Balancer To Requester Worker Worker Worker Worker To Requester 37

Requester The requester sends Requests to the balancer. type Request struct { fn func() int // The operation to perform c chan int // The channel on which to return the result An artificial but illustrative simulation of a requester. func requester(work chan Request) { c := make(chan int) for { time.sleep(rand.int63n(nworker * 2e9)) // spend time work <- Request{workFn, c // send request result := <-c // wait for answer furtherprocess(result) 38

Worker The balancer will send each request to the most lightly loaded worker. This is a simple version of a Worker but it's plausible. func (w *Worker) work(done chan *Worker) { for { req := <-w.requests // get Request from load balancer req.c <- req.fn() // call fn and send result to requester done <- w // tell balancer we've finished this job The channel of requests (w.requests) delivers requests to each worker. The balancer tracks the number of pending requests as a measure of load. Note that each response goes directly to its requester. 39

Balancer The load balancer needs a pool of workers and a single channel to which requesters can send work. 40 type Pool []*Worker type Balancer struct { pool Pool done chan *Worker At this point, the balancer is very easy. func (b *Balancer) balance(work chan Request) { for { select { case req := <-work: // received a Request... b.dispatch(req) //...so send it to a Worker case w := <-b.done: // a worker has finished a request... b.completed(w) //...so update its info

A heap of channels How do we implement dispatch and completed? We can use a heap to choose the most lightly loaded worker by attaching the necessary methods to type Pool (Len, Push, Pop, Swap, Less). That's easy; here for instance is Less: func (p Pool) Less(i, j int) bool { return p[i].pending < p[j].pending And in each Worker, we keep a count of pending operations. type Worker struct { requests chan Request // work to do (a buffered channel) pending int // count of pending tasks index int // index in the heap 41

Use the heap to maintain balance 42 The implementation of dispatch and completed is easy: // Send Request to worker func (b *Balancer) dispatch(req Request) { w := heap.pop(&b.pool).(*worker) // least loaded worker... w.requests <- req //...is assigned the task w.pending++ // one more in its queue heap.push(&b.pool, w) // put it back in the heap // Job is complete; update heap func (b *Balancer) completed(w *Worker) { w.pending-- // one fewer in its queue heap.remove(&b.pool, w.index) // remove it from heap heap.push(&b.pool, w) // put it back where it belongs Channels are first-class values. We've built a heap of channels to multiplex and load balance.

Demo

Discussion Every operation blocks, yet this system is highly concurrent. The combination of communication and synchronization is a powerful tool. {Closure, channel pairs are a nice way to pass work around. The closure says what to do; the channel lets the answer flow directly back to the requester. Channels can be part of other data structures and can be passed between goroutines. With very little work, you could use network channels or RPCs to make this a distributed, networked load balancer. (Although closures don't work across the network, RPCs help.) 44

Conclusion

Go is different Objects are not always classes Inheritance is not the only way to structure a program You don't need to specify everything in advance (And you shouldn't need to anyway) Implicitly satisfying behavior leads to pleasant surprises Concurrency is not just parallelism But it is a great way to structure software 46

Go is more productive Go can make programming very productive: - any type can be given methods, which opens up interesting design possibilities. - most of the bookkeeping of type-driven programming is done automatically. - the structuring power of concurrent programming leads easily to correct, scalable server software. Such properties make Go programs more malleable, more adaptable, less brittle. More at http://golang.org 47

Go is more fun Go comes with T-shirts, tattoos and stickers. 48

Live waving Please ask questions about this session on Google Wave: http://bit.ly/go2010io More about Go at http://golang.org 49