Text file
talks/2012/chat.slide
1 Go: code that grows with grace
2
3 Andrew Gerrand
4 Google Sydney
5 http://andrewgerrand.com
6 @enneff
7 https://go.dev
8
9 * Video
10
11 A video of this talk was recorded at Øredev in Malmö, Sweden in November 2012.
12
13 .link http://vimeo.com/53221560 Watch the talk on Vimeo
14
15 * Go
16
17 You may have heard of Go.
18
19 It's my favorite language. I think you'll like it, too.
20
21 * What is Go?
22
23 An open source (BSD licensed) project:
24
25 - Language specification,
26 - Small runtime (garbage collector, scheduler, etc),
27 - Two compilers (`gc` and `gccgo`),
28 - 'Batteries included' standard library,
29 - Tools (build, fetch, test, document, profile, format),
30 - Documentation.
31
32 As of September 2012 we have more than 300 contributors.
33
34 * Go is about composition
35
36 Go is Object Oriented, but not in the usual way.
37
38 - no classes (methods may be declared on any type)
39 - no subtype inheritance
40 - interfaces are satisfied implicitly (structural typing)
41
42 The result: simple pieces connected by small interfaces.
43
44 * Go is about concurrency
45
46 Go provides CSP-like concurrency primitives.
47
48 - lightweight threads (goroutines)
49 - typed thread-safe communication and synchronization (channels)
50
51 The result: comprehensible concurrent code.
52
53 * Go is about gophers
54
55 .image chat/gophers.jpg
56
57 * Core values
58
59 Go is about composition, concurrency, and gophers.
60
61 Keep that in mind.
62
63 * Hello, go
64
65 .play chat/support/hello.go
66
67 * Hello, net
68
69 .play chat/support/hello-net.go
70
71 * Interfaces
72
73 Hey neato! We just used `Fprintln` to write to a net connection.
74
75 That's because a `Fprintln` writes to an `io.Writer`, and `net.Conn` is an `io.Writer`.
76
77 .code chat/support/hello-net.go /Fprintln/
78 .code chat/support/defs.go /Fprintln/
79 .code chat/support/defs.go /type.Writer/,/^}/
80 .code chat/support/defs.go /type.Conn/,/^}/
81
82 * An echo server
83
84 .play chat/support/echo-no-concurrency.go
85
86 * A closer look at io.Copy
87
88 .code chat/support/echo-no-concurrency.go /Copy/
89 .code chat/support/defs.go /Copy/,/func/
90 .code chat/support/defs.go /type.Conn/,/^}/
91 .code chat/support/defs.go /type.Writer/,/^}/
92 .code chat/support/defs.go /type.Reader/,/^}/
93
94 * Goroutines
95
96 Goroutines are lightweight threads that are managed by the Go runtime. To run a function in a new goroutine, just put `"go"` before the function call.
97
98 .play chat/support/goroutines.go
99
100 * A concurrent echo server
101
102 .play chat/support/echo.go
103
104 * "Chat roulette"
105
106 In this talk we'll look at a simple program, based on the popular "chat roulette" site.
107
108 In short:
109
110 - a user connects,
111 - another user connects,
112 - everything one user types is sent to the other.
113
114 * Design
115
116 The chat program is similar to the echo program. With echo, we copy a connection's incoming data back to the same connection.
117
118 For chat, we must copy the incoming data from one user's connection to another's.
119
120 Copying the data is easy. As in real life, the hard part is matching one partner with another.
121
122 * Design diagram
123
124 .image chat/diagrams.png
125
126 * Channels
127
128 Goroutines communicate via channels. A channel is a typed conduit that may be synchronous (unbuffered) or asynchronous (buffered).
129
130 .play chat/support/chan.go
131
132 * Select
133
134 A select statement is like a switch, but it selects over channel operations (and chooses exactly one of them).
135
136 .play chat/support/select.go
137
138 * Modifying echo to create chat
139
140 In the accept loop, we replace the call to `io.Copy`:
141
142 .code chat/support/echo.go /for {/,/\n }/
143
144 with a call to a new function, `match`:
145
146 .code chat/tcp-simple/chat.go /for {/,/\n }/
147
148 * The matcher
149
150 The `match` function simultaneously tries to send and receive a connection on a channel.
151
152 - If the send succeeds, the connection has been handed off to another goroutine, so the function exits and the goroutine shuts down.
153 - If the receive succeeds, a connection has been received from another goroutine. The current goroutine then has two connections, so it starts a chat session between them.
154
155 .code chat/tcp-simple/chat.go /var.partner/,/^}/
156
157 * The conversation
158
159 The chat function sends a greeting to each connection and then copies data from one to the other, and vice versa.
160
161 Notice that it launches another goroutine so that the copy operations may happen concurrently.
162
163 .code chat/tcp-simple/chat.go /func.chat/,/^}/
164
165 * Demo
166
167 * Error handling
168
169 It's important to clean up when the conversation is over. To do this we send the error value from each `io.Copy` call to a channel, log any non-nil errors, and close both connections.
170
171 .code chat/tcp/chat.go /func.chat/,/^}/
172 .code chat/tcp/chat.go /func.cp/,/^}/
173
174 * Demo
175
176 * Taking it to the web
177
178 "Cute program," you say, "But who wants to chat over a raw TCP connection?"
179
180 Good point. Let's modernize it by turning it a web application.
181
182 Instead of TCP sockets, we'll use websockets.
183
184 We'll serve the user interface with Go's standard `net/http` package, and websocket support is provided by the `websocket` package from the `go.net` sub-repository,
185
186 * Hello, web
187
188 .play chat/support/hello-web.go
189
190 * Hello, WebSocket
191
192 .code chat/support/websocket.js
193 .play chat/support/websocket.go
194
195 * Using the http and websocket packages
196
197 .code chat/http/chat.go /package/,/^}/
198
199 * Serving the HTML and JavaScript
200
201 .code chat/http/html.go /import/
202 .code chat/http/html.go /func/,/<script>/
203 .code chat/http/html.go /websocket.=/,/onClose/
204 .code chat/http/html.go /<\/html>/,$
205
206 * Adding a socket type
207
208 We can't just use a `websocket.Conn` instead of the `net.Conn`, because a `websocket.Conn` is held open by its handler function. Here we use a channel to keep the handler running until the socket's `Close` method is called.
209
210 .code chat/http-noembed/chat.go /type.socket/,/END/
211
212 * Struct embedding
213
214 Go supports a kind of "mix-in" functionality with a feature known as "struct embedding". The embedding struct delegates calls to the embedded type's methods.
215
216 .play chat/support/embed.go /type/,$
217
218 * Embedding the websocket connection
219
220 By embedding the `*websocket.Conn` as an `io.ReadWriter`, we can drop the explicit `socket` `Read` and `Write` methods.
221
222 .code chat/http/chat.go /type.socket/,/END/
223
224 * Demo
225
226 * Relieving loneliness
227
228 What if you connect, but there's noone there?
229
230 Wouldn't it be nice if we could synthesize a chat partner?
231
232 Let's do it.
233
234 * Generating text with markov chains
235
236 .code chat/support/markov.txt
237
238 * Generating text with markov chains
239
240 Fortunately, the Go docs include a markov chain implementation:
241
242 .link /doc/codewalk/markov go.dev/doc/codewalk/markov
243
244 We'll use a version that has been modified to be safe for concurrent use.
245
246 .code chat/markov/markov.go /Chain/,/{/
247 .code chat/markov/markov.go /Write/,/{/
248 .code chat/markov/markov.go /Generate/,/{/
249
250 * Feeding the chain
251
252 We will use all text that enters the system to build the markov chains.
253 To do this we split the socket's `ReadWriter` into a `Reader` and a `Writer`,
254 and feed all incoming data to the `Chain` instance.
255
256 .code chat/markov/chat.go /type.socket/,/^}/
257 .code chat/markov/chat.go /var.chain/,/^}/
258
259 * The markov bot
260
261 .code chat/markov/chat.go /\/\/.Bot/,/^}/
262 .code chat/markov/chat.go /type.bot/,/^}/
263 .code chat/markov/chat.go /func.+bot.+Write/,/^}/
264 .code chat/markov/chat.go /func.+bot.+speak/,/^}/
265
266 * Integrating the markov bot
267
268 The bot should jump in if a real partner doesn't join.
269 To do this, we add a case to the select that triggers after 5 seconds, starting a chat between the user's socket and a bot.
270
271 .code chat/markov/chat.go /func.match/,/^}/
272
273 The `chat` function remains untouched.
274
275 * Demo
276
277 * One more thing
278
279 * TCP and HTTP at the same time
280
281 .code chat/both/chat.go /func main/,/^}/
282 .code chat/both/chat.go /func netListen/,/^}/
283
284 * Demo
285
286 * Discussion
287
288 * Further reading
289
290 All about Go:
291
292 .link / go.dev
293
294 The slides for this talk:
295
296 .link /talks/2012/chat.slide go.dev/talks/2012/chat.slide
297
298 "Go Concurrency Patterns" by Rob Pike:
299
300 .link /s/concurrency-patterns go.dev/s/concurrency-patterns
301
View as plain text