Sei sulla pagina 1di 18

An overview of Go

by Dan Callahan Lets start at the beginning: What is Go? Go is a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language ! "t is a systems language competiti#e $ith C, C%%, and &a#a, but designed to deal gracefully $ith concurrency 'o $it: Go makes much more sense for the class of problems that C%% $as originally intended to sol#e ! ()ruce *ckel Go $as released by Google in late +,,-, and .ersion / , should land in the first fe$ months of +,/+

Why should you care?


0ou should care about Go for fi#e reasons: / + 2 3 4 "t has an impeccable pedigree "t embodies an e1tremely pragmatic design philosophy "t implements many inno#ati#e ideas "t can already be used for real $ork "t has an absolutely fantastic mascot

Gos Pedigree
Go is being de#eloped by )ell Labs #eterans augmented by a handful of other brilliant engineers 'he core team includes:

Rob Pike 56'789, :lan - from )ell Labs; Ken Thompson 5C, 6ni1, :lan - from )ell Labs; Russ o! 5:lan - from )ell Labs, <*+, Google Code =earch; Rober" Griesemer 5>ot=pot, .9; #an Taylor 5GCC, Gold;

'he teams e1perience is humbling "f nothing else, subscribe to the Go blog 0ou will learn something

Gos Pragma"ic $esign Philosophy


Go is an e1tremely pragmatic language ?ne of its central design tenets is the idea that interpreted languages 5:erl, :ython, <uby, etc ; are popular not due to any inherent property of being interpreted, but rather because they often ha#e better syntactic constructs, are more e1pressi#e than their compiled counterparts, and dont force de#elopers to sit through long compile times

)y taking these lessons into account, Go hopes to offer the de#eloper8time efficiency of a language like :ython and the run8time efficiency of C 7or e1ample:

*#en though Go is a systems language, it uses garbage collection Go has been designed to compile extremely @uickly Gos synta1 is clean and minimal Go offers first8class functions 7unctions in Go are closures 7unctions in Go can return multiple #alues 7unction definitions can ha#e named return parameters Go offers sane error handling, in contrast to many languagesA model of thro$ing and catching e1ceptions

Lets look at a fe$ of these more closely

Quick Compile Times


Go programs are structured in a manner that drastically limits the number of passes re@uired to produce a binary By / C G>D dual8core laptop compiles pkg/math 5E+ files, 4 FL?C; in under / second:
$ time make --quiet make --quiet 0.89s user 0.08s system 97% cpu 0.991 total

Clean Syntax
)elo$ is a simple hello, $orld! in Go
package main import "fmt" func main ! " fmt.#rintln "$ello% "! &

'he anatomy of this program should be self8e#ident: "t declares that it is a member of the package main, imports any other packages it needs, and then defines a function called main, $hich is e1ecuted $hen the compiled program is in#oked "ts $orth pointing out the use of 6nicode )y definition, Go source files are encoded in 6'789, $hich makes it easy to use 6nicode literals >a#e you e#er $anted to name a #ariable G? Well, no$ you can

First Class Functions


"n Go, functions can be created or passed around like any other structure "n the code belo$, "#e defined t$o unary functions: 'ou(le and square *ach accepts a single int for input and returns a single int "#e also defined apply, $hich accepts a t$o arguments: a function, and an integer "t then calls the function and returns an integer
package main import "fmt" func 'ou(le ) int! int " return ) * ) & func square ) int! int " return ) + ) & func apply f func int! int% ) int! int " return f )! & func main ! " fmt.#rintln apply 'ou(le% ,!! fmt.#rintln apply square% ,!! &

)ecause Go is strongly and statically typed, function declarations must e1plicitly name the types of their inputs and return #alues 'hus, func apply f func int! int% ) int! int creates a ne$ function named apply $hich takes t$o inputs, a func int! int called f and an int called ) "t then returns an int 0ou can read func int! int the same $ay: "ts a function that accepts an integer and returns an integer With that information, the compiler is able to #erify that e#erything in the program is of the e1pected type "ts $orth noting that Go does not do implicit or automatic type coercion

Closures
H closure is Iust a function that can reference #ariables that $ould typically be considered outside of its scope 'o illustrate, the code belo$ calculates the first fe$ 7ibonacci numbers using a closure
package main func fi( ! func ! int " a% ( -. 0% 1 return func ! int " a% ( . (% a*( return ( &

& func main ! " f -. fi( ! println f !% f !% f !% f !% f !! &

'hat might look a bit $eird 'o re#ie$, note that named function definitions ha#e three parts: / + 2 'he func key$ord 'he name of the function, its inputs, and their types, like square ) int! 'he functions return type, like int

=o func fi( ! func ! int abo#e is creating a function named fi( that doesnt ha#e any inputs, and $hich returns a func ! int H func ! int is, in turn, a function that doesnt ha#e any inputs, and $hich returns an integer 'hus, $hen $e in#oke fi( ! $e get another function When $e in#oke that, $e get an integer )ecause functions in Go are closures, the function returned by fi( ! has access to the #alues of a and (, e#en though they $ere defined outside of the inner function itself

Gos #nnova"ions
'he follo$ing items arent necessarily uni@ue to Go, but they are distinguishing features

Go ships $ith its o$n pretty printer, gofmt Go ships $ith an old8to8ne$ Go compiler, gofi1 Go sports a brilliantly light$eight type system Go has per#asi#e, primiti#e support for concurrency Go makes it easy to defer e1ecution of a function until the end of a block

'he type system and concurrency features are $orthy of their o$n dedicated articles, so lets look at the other items

Gofmt, the Go Pretty-Printer


Go is some$here bet$een C and :ython in the rigidity of its synta1 Whitespace is insignificant and semicolons can be omitted, but the opening brace of a construct must be on the same line as that construct =till, Go maintains high degree of readability across authors thanks to gofmt, a command line tool that pretty8prints Go source code in a single, consistent style 'ake the follo$ing #ersion of the 7ibonacci program from abo#e "t still compiles and runs perfectly, but it has semicolons e#ery$here, horribly inconsistent indentation, and e#en combines t$o statements on one line $ith a% ( . (% a*(/ return (/
package main

func fi( ! func ! int " a% ( -. 0% 1/ return func ! int " a% ( . (% a*(/ return (/ & & func main ! " f -. fi( !/ println f !% f !% f !% f !% f !!/ &

?ne pass through gofmt, and out pops:


package main func fi( ! func ! int " a% ( -. 0% 1 return func ! int " a% ( . (% a*( return ( & & func main ! " f -. fi( ! println f !% f !% f !% f !% f !! &

Gofix, the Old-to-Ne

Go Compiler

Hs Go is still under rapid de#elopment, its not uncommon for components of the standard library to change in back$ards8incompatible $ays <ather than paper o#er these changes $ith shims, the Go team ships gofi), a compiler that reads in Go code $ritten against old H:"s, and updates it to use ne$er ones 7or e1ample, earlier this year, the code belo$ $ould compile, parse a 6<L, and print out the #alue of the parameter q:
package main import "http" func main ! " url% 0 -. http.#arse123 "http-//e)ample.com/search4q.foo"! println url.5uery !.6et "q"!! &

>o$e#er, trying to compile that code today fails:


$ 7g ol'.go ol'.go-7- un'efine'- http.#arse123

'his fails because the #ersion of Go released in =eptember +,// took all of the url8related functions out of the http package and put them in their o$n url package <unning the code through gofi) updates it to use the renamed functions: 4

package main import "url" func main ! " url0% 0 -. url.#arse "http-//e)ample.com/search4q.foo"! println url0.5uery !.6et "q"!! &

Jote that import "http" changed into import "url" and http.#arse123 $as changed into url.#arse ?ne of the more subtle details is that my #ariable, url, $as automatically renamed to url0 to a#oid clashing $ith the ne$ import statement >o$ cool is that? "f youre coming from :ython, you can think of gofi) as being similar to 8to9

!eferred "xecution
'ake the follo$ing program:
package main func goo'(ye ! " println "6oo'(ye:"! & func main ! goo'(ye println println println println & " ! ";our"! "<hree"! "=ne"! "<>o"!

When run, it prints out fi#e lines in their order of appearance in the file:
$ ./'efer1 6oo'(ye: ;our <hree =ne <>o

)ut $hat if goo'(ye ! handled some sort of cleanup, like closing a file, and $e $anted it to run at the end of the function We could mo#e it to the end, but that might mean separating it from the thing that its cleaning up after :ython has Conte1t Banagers 5>ith blocks; to handle this sort of scenario Go has the 'efer statement )y prefi1ing any function call $ith 'efer, that call gets @ueued and only runs right before the enclosing function completes Lets look at $hat happens if $e defer the call to goo'(ye !:
func main ! " 'efer goo'(ye ! println ";our"!

&

println "<hree"! println "=ne"! println "<>o"!

Jo$ running the program prints goodbyeK! at the end:


$ ./'efer8 ;our <hree =ne <>o 6oo'(ye:

Hnd all it took $as adding a simple 'efer key$ord in front of the call "ts also $orth noting that you can defer multiple calls $ithin a function, and $hen that function completes, theyre e#aluated in a last in, first out 5L"7?; order 'hus, by deferring the first t$o calls to println !L
func main ! " 'efer goo'(ye ! 'efer println ";our"! 'efer println "<hree"! println "=ne"! println "<>o"! &

L$e can get the correct! ordering in the output:


$ ./'efer9 =ne <>o <hree ;our 6oo'(ye:

While most immediately useful for closing files or tracing e1ecution, deferred functions can also be used to inspect and modify named return #alues 'his is possible because deferred functions e1ecute after their parent has completed, but before it actually returns #alues to its caller

%sing Go for Real Work


Go currently runs $ell on 2+ and C3 bit Linu1, 7ree)=D, and Bac ?= M :orts to Linu1NH<B and Windo$sN19C are in the $orks Ht the time of $riting, Go is only t$o years old =o $hos using it? Google, for one Were already using Go internally at Google for some production stuff! (<ob :ike, Bay +,/,

>eroku has also been using Go to build DooDer, a consistent, highly8a#ailable data store 'o @uote Feith <arick, 'his is the first significant thing $e#e done in Go, but it $ont be the last Go has been an absolute Ioy to use ! "ts also $orth noting that at the time of $riting t$o of the top three competitors in 'he H" Challenge are $ritten in Go Lastly, Google Hpp *ngine has e1perimental support for deploying proIects $ritten in Go

Gos &an"as"ic 'asco"


"f youre familiar $ith :lan -, youre already familiar $ith Glenda, the :lan - )unny

"n that same #ein, " present the Go Gopher:

'he Go Gopher has also made appearances as collectable toysL

Land as a pair of rather special >allo$een costumes:

"snt it $onderful?

oncurrency in "he Go Programming (anguage


:ublished 'hursday, December +-th, +,// 'his article is based on the second half of a presentation " ga#e at :yBJtos in December, +,// Go sports t$o features specifically designed to ease concurrent programming: Goroutines and Channels

Wha" is a Gorou"ine?
<ob :ike describes goroutines as being kind of like threads, but lighter8$eight ! 'heyre similar to $hat other languages might call green threads! or fibers,! but ha#e enough distinguishing features to merit their o$n name 'he basic idea is that your Go program can automatically spa$n a handful of nati#e threads or processes, and then automatically allocate goroutines bet$een them at runtime Hny goroutine can e1ecute on any thread or process, and any goroutine can dynamically mo#e from one thread or process to another 'hat means that as soon as a thread blocks, the other goroutines on that thread can be seamlessly mo#ed to other, unblocked threads, and continue running 'he language itself pro#ides great syntactic support for kicking off goroutines during the e1ecution of your program 7or e1ample, imagine you $anted to build an application that timed ho$ long it took to bre$ some coffee or tea "t might look like this:
package main import "time" func ?s2ea'y >hat string% secon's int7@! " time.Aleep secon's + 1e9! // nanosecon's println >hat% "is rea'y:"! & func main ! println ?s2ea'y ?s2ea'y println & " "3etBs go:"! "Coffee"% 7! "<ea"% 8! "?Bm 'one here."!

'he program e1poses one function, ?s2ea'y, $hich takes in t$o #ariables: $hat its $aiting for, and ho$ many seconds to $ait Hfter the specified time passes, it prints out a message notifying you that something is ready

<unning this program produces the follo$ing output, annotated $ith the time at $hich each line gets printed:
$ ./(re>1 3etBs go: Coffee is rea'y: <ea is rea'y: ?Bm 'one here D D D D 00-00 00-07 00-08 00-08

*#erything happens synchronously and in order: Lets goK! gets printed immediately, then the program pauses for C seconds, prints out Coffee is readyK!, pauses another t$o seconds, prints out 'ea is readyK!, then prints "m done here ! and e1its )ut $hat if $e $anted to start bre$ing the tea and coffee at the same time? Wed need some $ay to start both calls to ?s2ea'y asynchronously 'hats $here goroutines come in :refi1ing any e1pression or function in#ocation $ith the key$ord go causes it to be e1ecuted in its o$n goroutine, on an aribitrary thread Lets try it:
func main ! " println "3etBs go:"! go ?s2ea'y "Coffee"% 7! go ?s2ea'y "<ea"% 8! println "?Bm 'one here."! &

<unning this yields:


$ ./(re>8 3etBs go: D 00-00 ?Bm 'one here. D 00-00

WaitK 'hats not rightK "t immediately printed Lets goK!, then "m done here ! and then e1ited What happened to the ?s2ea'y calls? )oth of those calls fired up a goroutine $hich began e1ecuting in the background 6nforuntately, before those goroutines could do anything useful, e1ecution hit the end of the main function and the program terminated, taking the goroutines $ith it We really $ant to $ait until both goroutines finish before e1iting, but $e dont kno$ ho$ to do that yet 7or no$, Iust to pro#e that e#erything is $orking, lets Iust try $aiting a little bit at the end before $e e1it:
func main ! " println "3etBs go:"! go ?s2ea'y "Coffee"% 7! go ?s2ea'y "<ea"% 8! println "?Bm 'one here."! time.Aleep 7 + 1e9! &

Which, $hen run, prints out:


$ ./(re>9 3etBs go: ?Bm 'one here. D 00-00 D 00-00

/,

<ea is rea'y: D 00-08 Coffee is rea'y: D 00-07

=o Iust like before, the t$o println statements in main get e1ecuted right off the bat '$o seconds later, $e see 'ea is readyK! 7our seconds later its follo$ed by Coffee is readyK! 'hen, one second later, the call to time.Aleep 7 + 1e9! finishes and the program e1its 6sing time.Aleep like that is a terrible idea, but $ere kind of limited $ithout being able to send or recei#e messages from the goroutines to kno$ $hen theyre done >o$e#er, $e actually dont need that to do useful thingsK "magine a $eb ser#er: "t simply loops fore#er $aiting for a re@uest When one comes in, it processes it, sends a response, and goes back to $aiting "f you $anted to get fancy, you might handle each re@uest in its o$n thread, $hich keeps things neat and tidy, at least in concept 'he do$nside is that you then ha#e to deal $ith gnarly thread management issues "ck What if $e used goroutines instead instead of threads? *ach goroutine $orks, conceptually, like its o$n thread, but they can be multiple1ed on top of any number of nati#e threads or processK Hnd the Go language automatically handles resource management for you 'heres e#en a built in http package $hich uses this kind of architecture behind the scenes:
package main import "fmt" "http" ! func han'ler > http.2esponseEriter% r +http.2equest! " fmt.;printf >% "$i there% ? loFe %s:"% r.123.#athG1-H! & func main ! " http.$an'le;unc "/"% han'ler! http.3istenIn'AerFe "-8080"% nil! &

"f you run that and #isit http-//localhost-8080/cake, youll see >i there, " lo#e cakeK! in your bro$ser, since http.$an'le;unc "/"% han'ler! ensures that all re@uests get passed off to the han'ler function, $hich simply displays that message Digging in to the source for the http package $ill re#eal that it takes each incoming re@uest, spins up a goroutine to handle it, and then goes back to listening 'hus, a great use of goroutines $ithout needing to kno$ ho$ to communicate $ith them $hile they run =till, there are situations $here you need to communicate $ith the goroutines, as per the coffee N tea bre$ing code abo#e Luckily, Go pro#ides channels to do Iust that

//

Wha" is a channel?
H channel is a type8safe pipe for communicating bet$een different parts of your program Lets start $ith an impro#ed #ersion of the bre$ing program as an e1ample:
package main import "time" func ?s2ea'y >hat string% secon's int7@% ch chanJ- (ool! " time.Aleep secon's + 1e9! // nanosecon's println >hat% "is rea'y:"! ch J- true & func main ! " ch -. make chan (ool! println "3etBs go:"! go ?s2ea'y "Coffee"% 7% ch! go ?s2ea'y "<ea"% 8% ch! println "?Bm 'one here."! for i -. 0/ i J 8/ i** " J-ch & &

'ake a second to read that and see if you can spot the differences 7or one, ?s2ea'y no$ takes a third parameter, ch, $hich is a chanJ- (ool, meaning a channel for sending (ool data ! =econdly, after printing out that its done bre$ing $hate#er, it calls ch J- true, $hich is an e1pression meaning send true do$n the channel ch ! Jo$ lets look at main, $hich starts by creating a (ool channel $ith ch -. make chan (ool! 'his same channel is then passed to each of the t$o ?s2ea'y calls Lastly, instead of doing something terrible like $aiting for E seconds, the program calls J-ch t$ice, $hich Iust means read a #alue from from ch ! =ince channels are blocking and unbuffered by default, reading from a channel $ith J-ch $ill sit and $ait until some other goroutine tries to $rite to the channel $ith, say, ch J- true 'he in#erse is also true: senders $ill block and $ait until a recei#er is ready =ince $e kno$ $e only spun up t$o goroutines, $e can safely e1it after t$o #alues pop out of ch, since sending on ch is the last thing each goroutine does before reaching completion 'o step back a bit, you can think of goroutines as being similar to type8safe 6ni1 pipes Lets take that analogy and e1tend it
$ echo "hello >orl'" K >c -c 18 $ echo "hello >orl'" K se' -e Bs/hello/goo'(ye/gB K >c -c 1@

/+

'he shell commands abo#e $ork like they do since echo Iust takes a string, slaps a Ln character on the end, and spits it back out Bean$hile >c -c reads in data and counts the number of characters 'hus, it counts /+ in the first instance 54 % 4 % a space % a ne$line; =imilarly, the se' in#ocation takes its input and replaces any occurances of hello! $ith goodbye!, lengthening the original string by + What if $e $anted to simulate that sort of a pipeline in Go? 7irst, lets define functions to replace echo, se', and >c *ach one $ill take a channel for input, and a channel for output:
package main import "rege)p" "strconF" ! func echo in chan string% out chan string! " out J- J-in * "Ln"! & func se' in chan string% out chan string! " re -. rege)p.MustCompile "hello"! out J- re.2eplaceIllAtring J-in% "goo'(ye"! & func >c in chan string% out chan string! " out J- strconF.?toa len J-in!! &

"n the abo#e functions, echo simply reads from its input channel, adds a ne$line to the end of it $ith J-in * "Ln", and then sends the result to the out channel 'he se' function $orks similarly, first compiling a regular e1pression that matches hello, and then calling that rege1s 2eplaceIllAtring method 'he method is told to grab a string from the in channel and use goodbye! as the replacement for matches 'he result gets sent to the out channel Lastly, >c simply reads from the input channel 5J-in;, then gets the length of the input $ith len, and lastly con#erts the integer length into a string $ith strconF.?toa before sending the result on the out channel 'he main function is simple, but a bit #erbose
func main ! " ch1 -. make ch8 -. make ch9 -. make ch@ -. make chan chan chan chan string! string! string! string!

go echo ch1% ch8! go se' ch8% ch9! go >c ch9% ch@! ch1 J- "hello >orl'" println J-ch@!

/2

&

"t simply makes four channels, and hooks them up so that the output of echo is the input of se', and the output of se' is the input of >c *ach of those subfunctions get started in their o$n goroutines, and then sit and $ait for input 'he string hello $orld! gets sent on ch1, $hich flo$s through echo, then se', then >c and out on ch@ 'he result, /3!, gets printed:
$ /pipes1 1@

*1plicitly specifying the input and output channels is needlessly #erbose We ha#e to gi#e each function an input channel, but if it made and returned its o$n output channel, then $e could tri#ially chain together as many functions as $e $ant Lets do that:
package main import "rege)p" "strconF" ! func echo in chan string! chan string " out -. make chan string! go func ! " out J- J-in * "Ln"! & ! return out & func se' in chan string! chan string " out -. make chan string! re -. rege)p.MustCompile "hello"! go func ! " out J- re.2eplaceIllAtring J-in% "goo'(ye"! & ! return out & func >c in chan string! chan string " out -. make chan string! go func ! " out J- strconF.?toa len J-in!! & ! return out &

'his might look comple1, but its really not too different from the pre#ious code 'he signatures changed to Iust accepting a single chan string, each function starts $ith creating an output channel, and each function ends by returning that channel "n the middle, the real $ork! gets $rapped in an anonymous function $hich gets in#oked in a goroutine 'his means that $hen you call something like echo, it immediately returns its ne$ly8made output channel, and as a side effect, spins off a goroutine to process any data that gets sent on the in /3

channel "ts basically saying ?kay, "m ready and $aiting on in When " get something, "ll gi#e it back to you on this channel that "m returning ! Jote that because functions in Go are closures, $e didnt ha#e to e1plicitly pass in a reference to the input channel, in, $hen $e defined an anonymous $orker function <ather, because in is #isible in scope $here $e defined the anonymous function, that function is able to see it With that restructuring in place, our main function looks much more sensible:
func main ! " in -. make chan string! out -. >c se' echo in!!! inJ-"hello >orl'" println J- out! &

We make an input channel, then $e get an output channel by composing our filters: out -. >c se' echo in!!! Hgain, because the output of echo in! is a channel, $e can use it as the input to se', and so on Hnd it $orks e1actly like you $ould e1pect:
$ ./pipes8 1@

7unctions that start goroutines and return channels are a some$hat uni@ue and interesting Go idiom

)ow do channels and gorou"ines work "oge"her?


Channels and goroutines $ork together to implement a much more sane model of concurrency than traditional threads and shared memory 'he central idea is that, for unbuffered channels, the act of reading and $riting across a channel forces t$o goroutines to, at that moment, be synchroniDed ?ther$ise, things are free to e1ecute concurrently or in parallel 'his paradigm is often e1pressed as: Do not communicate by sharing memoryO instead, share memory by communicating ( *ffecti#e Go 7or a some$hat silly e1ample of channels and goroutines $orking together, check out this prime number sie#e:
package main func 6enerate ch chanJ- int! " for i -. 8/ / i** " ch J- i & & func ;ilter in J-chan int% out chanJ- int% prime int! "

/4

for " i -. J-in if i%prime :. 0 " out J- i & & & func main ! " ch -. make chan int! go 6enerate ch! for i -. 0/ i J 10/ i** " prime -. J-ch print prime% "Ln"! ch1 -. make chan int! go ;ilter ch% ch1% prime! ch . ch1 & &

simply starts at + and sends e#er increasing numbers out on a gi#en channel 7irst +, then 2, then 3, and so on
6enerate ;ilter sits in bet$een prime input parameter

t$o channels and silently drops any number thats di#isible by its ?ther$ise, it Iust passes the number along H ;ilter in% out% 8!, for instance, $ould not let any multiples of + through it 'hus, $hen hooked up to the output of 6enerate, first 2, then 4, then E, $ould pop out the other end Can you see $here this is going? We $ant to build a pipeline that successi#ely filters each prime, so that $ith each number popping out the end, $e sa#e it, and then add on a filter for its o$n multiples:
G6enerateH -N 8 G6enerateH -N G;ilter 8!H -N 9 G6enerateH -N G;ilter 8!H -N G;ilter 9!H -N ,

Land so on >ence the loop in the main function, $hich successi#ely reads from the rightmost end of the pipeline, prints that #alue, and then adds on a filter for it
$ ./primes 8 9 , 7 11 19 17 19 89 89

/C

)ecause all of the $ork is happening in goroutines, as soon as any t$o adIacent goroutines are ready, a ne$ #alue can begin tra#ersing through the pipeline 'he adIacent goroutines synchroniDe upon e1changing data

hannels can also be mul"iple!ed


Hny number of goroutines can $rite to a single channel, and any number of goroutines can read from a single channel Go e#en has a special select statement $hich, gi#en a list of channels, reads from and e1ecutes a block for a random, $aiting channel 'his allo$s channels to be easily de8multiple1ed 7or another e1ample, lets use the random selection amongst $aiting channels to implement a ridiculous random number generator:
package main func main ! " ch1 -. make chan int! ch8 -. make chan int! go func ! " for " J-ch1 & & ! for " select " case ch1 J- 0print 0! case ch1 J- 1print 1! case ch8 J- 8print 8! & & &

*1ecuting this prints out a random series of /s and ,s Why? Well, first $e set up t$o channels for integers, and then kick off a goroutine that does nothing but drain one of those channels 'hen $e loop infinitely, selecting one of the ready cases =ince the goroutine is al$ays $aiting to consume any #alue sent on ch1, either of the t$o case statements that send on ch1 could run )y definition, select chooses one those at random, creating a stream of random data )ecause nothing is e#er $aiting to read from ch8, the case that sends on ch8 is ne#er e1ecuted 'hese features make it easy to implement things like @ueues, signaling, etc

/E

*roader Applica"ions
*#en if you ne#er plan on using Go, Iust learning about goroutines and channels can pro#ide a rich mental model for designing concurrent systems "m particularly fond of this @uote describing the benefits of good notation: )y relie#ing the brain of all unnecessary $ork, a good notation sets it free to concentrate on more ad#anced problems, and, in effect, increases the mental po$er of the race (Hlfred Jorth Whitehead, Hn "ntroduction to Bathematics, /-// Hnd if youd like to go straight to the notations source, goroutines and channels take their inspiration from C H < >oares Communicating =e@uential :rocesses!, a formal language for describing patterns of interaction in concurrent systems

Py"hon and oncurrency


Puite a fe$ proIects e1ist to make concurrent programming easier in :ython "n particular:

)oth :yC=: and :ython8C=: implement C=: in :ython, and are some$hat acti#e 'he :ython8C=: proIect is currently planning on merging into :yC=: 'he ))Cs Famaelia is a frame$ork for doing *rlang8style concurrency in :ython =tackless :ython is a fork of C:ython $ith added support for tasklets! and channels

+"her Resources
6sing C=: is 'ony >oares book on C=:, a#ailable as a free :D7 'he Go $ebsite at golang org has absolutely fantastic resources, including great docs, a bro$ser8based playground! N pastebin, an interacti#e tour of the language, a great blog, and much more

redi"s
<andom )it Generator and Coffee N 'ea )re$ing applications inspired by the slides from day 2 of <ob :ikes Go course 'he Concurrent :rime =ie#e is from golang org

/9

Potrebbero piacerti anche