Tip:
Highlight text to annotate it
X
AMY: Welcome everyone who's just started
watching this broadcast.
And if you want to join in person, feel free to do.
There are a few extra slots left on the Hangout.
And there's a total of 10, so if you try to join and can't
manage it, you can still just watch the broadcast.
So let me introduce Proppy, otherwise known as Johan,
who's an App Engine dev rel.
He's been doing a lot of work with Go the language Go.
And this is Andrew, another App Engine dev rel.
And this is Dave who works on Go.
And my name's Amy.
And Proppy's going to give a presentation about building Go
apps on App Engine.
And we want this to be as interactive as possible, so we
encourage a few of you to join the Hangout if you feel like
it and ask questions as we go on.
And if you know the Go IRC channel, I think someone's
monitoring the questions on that as well.
ANDREW: And in the App Engine IRC channel as well.
AMY: All right, great.
So let's get started.
JOHAN EUPHROSINE: So it's a short presentation explaining
how to build a simple application
with Go on App Engine.
You can follow the slide along on proppy-go-ae.appspot.com.
So a bit of presentation about me.
My name is Johan Euphrosine.
I am working at Google Zurich.
I'm a developer program engineer on App Engine, which
means that I'm supporting the App Engine Developer
Community--
on the forums, on stack overflow, and also on IRC.
I write code for a new feature when there is new SDK release.
And I write batch code about best practices.
You can reach me through my Google+ profile at
profiles.google.com/proppy.
And here is a photo of me with more hair.
So what is App Engine?
So, quickly, App Engine allows you to scale your web
applications by running them on a Google infrastructure.
So you get to use the same back end as Gmail, Calendar,
and other Google properties exposed as API for your
application.
So recently, last year, we announced the Go Runtime as
experimental.
So the Go Runtime has a few unique properties compared to
other runtimes of App Engine, which are Python and Java.
So each runs native code.
It has a very low memory footprint, meaning that the Go
instance in App Engine usually consumes less memory than
other instances.
It's also faster to start, because since it's all
combined to a single binary, when App Engine starts your
application, it only has to read a single file.
Whereas with Java or Python, that's [INAUDIBLE]
your application.
And also there is [INAUDIBLE]
for concurrency.
By default, what happens when you deploy a Go application in
App Engine is that you spawn a Go routine, which is like with
thread on each request.
And when one request is doing some IO, it can process
another incoming request, meaning that you get to
consume less instance-hour, because your instance is more
used as there are more requests coming in.
The runtime doesn't necessarily need to spawn new
instances for a new Go request.
So a really simple example of how to write a web
application in Go.
So we just import a few packages.
So we'll import the font package for formatting string,
and the standard message to the package, which order you
to configure with an HTTP server.
There is an init function which is called when Your
application starts.
And in this init function, we just define a root to a URL,
which is called Hello.
And we map it to Handler, which is a function of Hello.
And then in this function, which takes two arguments, a
response writer to write our response and an HTTP request
just to get the request writer, we can write to the
response writer the exit we want to
write into the program.
In order to deploy it to App Engine, we need to create a
small manifest, which will describe your application.
We named your application.
Its name is gopher.
We tell which runtime we want to use.
We want to use Go.
We define some [INAUDIBLE]
for static files.
So if we want images [INAUDIBLE]
by your application, which has defined the best images that
we have, all the files which are located in
the directory images.
Same for doc.
Then we just map all URL to a Go application.
We can start an experiment with the application locally
by starting the development server, which is embedded in
the Go SDK.
And if we want to deploy it to App Engine, we could
[INAUDIBLE]
that and we give it the best application if we offer it to
App Engine.
AMY: I'm going to interrupt for just a second to
encourage--
we saw a few open Hangout slots.
So if anyone wants to ask any questions, please do join.
And welcome to Marcel who just joined in.
JOHAN EUPHROSINE: Welcome.
I've written a small demo of the
application we've just created.
So it just prints a [INAUDIBLE] string.
So now we'll try to do a bit more complicated thing.
So I don't know if you are reading the news like me, but
I always get it under checking both Hacker News and
Programming Reddit at the same time.
So we'll write a small application that will allow us
to check both at the same time without
opening two browser windows.
So what basically your application will be doing is
that it will fetch the JSON and XML stream of both Hacker
News and Programming Reddits and print it to a screen and
serve it as a text file.
So, first, in order to be able to fetch the Hacker News
stream, we'll import a module which is called App Engine URL
Fetch, which allows you to reach an API on App Engine
that allows us to fetch remote HTTP resources.
We'll be importing encoding in XML since Hacker News RSS feed
is encoded in XML.
And we define a new one there which is called hackernews,
and we bind it to the function hackernews.
And so here is how we can decode XML in Go.
So you can see here the structure of the RSS feed of
hackernews.
So there is a root element which is called RSS, then a
tiny amount which is called channel.
And for each item in this channel, there is an
[INAUDIBLE], which is called item with both a
title and a link back.
So we need to define some type that will
map to this XML structure.
So to do that, we just define plain structure in Go.
So the way you define structure in Go is just that
you create a new type declaration.
You give it a name.
And then you specify the main door of your structure.
So here, for example, we've just defined a structure for
the root elements.
And we said that a feed has one data element, which is
called channel.
So here we have this small annotation that allow to bind
or struct elements to the name of the type in the XML stream.
So what is a feed data?
A feed data is a channel, so it's a collection of XML item.
So here we just have a slice of item.
And each item is a title which is bound to the title type and
the URL, which is going to the root [INAUDIBLE].
And so here we have no hierarchy, a structure
hierarchy, which completely maps to our RSS feed format.
And the way we decode that in Go is quite simple, actually.
So we create a new function which is called
hackernewsItem, Which will take an App Engine context.
So an App Engine context is what is necessary to issue App
Engine API code, and which are the collection of items that
we use that we just defined on the previous slide.
So we just create a new URL fetch client, that will allow
us to make HTTP requests.
We issue a Get request to the feed URL, which is having the
RSS feed for Hacker News.
We handle the error, so we print an error in case we
don't manage to fetch a stream.
When we issue a Get request, we get a response back.
A response, we can read the response with
the body number .
And we have to make sure we close the body before our
function ends.
And for that in Go, we have a very useful keyword, which is
called "defer," which will allow you to specify function
codes to write that will get executed when
your function exits.
So whatever exit form that you have in your function, if you
return in the middle of your function or if you just go
through the function to the end, this
statement will get executed.
That line ensures that we close the body before the
function exits.
And we create a new decoder in order to decode
XML from the body.
We just [INAUDIBLE]
the root type that we defined on the slide before, which is
a root element of the hierarchy of the type for
defining the RSS feed.
And we call it the Decode function.
And what the Decode function will do is that it will pass
the XML stream and instantiate an element.
The [INAUDIBLE] corresponds correspond to the type that we
have given as an argument.
So when it will go on the RSS [INAUDIBLE], it will
instantiate an HNFeed object.
And when you see a [INAUDIBLE], it will
instantiate an HNFeedData structure.
And when we see Item [INAUDIBLE], it will
instantiate a new item object for each item that's been
encountered.
And so after that, we just have to return the data items
that we just passed.
And so the last thing that we need to do is to print it back
to the both other issues that we [INAUDIBLE].
So we just set Content-Type to say it's plain text.
And we just iterate on the objects that we get back from
the hackernews item function.
Here you can see how to make [INAUDIBLE].
So there is a range keyword that will return both an index
and an item for each item that we get back from the
hackernews item function [INAUDIBLE], which we just
print each item title and each item year.
So here we can see a little demo.
So here we can see all the links.
So this tells the URL of each item that is in the Hacker
News RSS feed.
So there's does anyone have any questions?
ANDREW: Proppy?
JOHAN EUPHROSINE: Yeah.
ANDREW: On the previous slide, what was the underscore in
that range statement?
JOHAN EUPHROSINE: Ah.
So good question, Andrew.
So the underscore is to say that we don't
want to use this parameter.
So it just binds the parameter--
since we have to explicitly say that we want to enter this
[INAUDIBLE].
So as a range keyword, we return two
items for each duration.
We have to say that we don't want to enter this parameter.
So we just-- the [INAUDIBLE], we say that we don't want to
enter this parameter.
ANDREW: So if I did have a variable there, it would be
assigned the index page?
JOHAN EUPHROSINE: Yeah.
So the range would return both each index and each element of
the collection that is on the right.
AMY: So I have a question for you, Proppy.
This code all looks pretty clean.
With what you've shown so far, what about it do you think is
maybe easier than writing in Python?
Or what maybe is harder?
How would you like to comment on that, or would you maybe
want to wait until you show a little more code?
ANDREW: I don't think he's gotten to the good part yet.
AMY: OK.
JOHAN EUPHROSINE: Yeah, that's an interesting question.
So in Python you have some legends that you need to
decode XML on the fly and map it to objects.
That's usually-- what you get back from that is a
dictionary, because you can't--
they only generate tags that Python could use without
knowing it, without knowing what you want to decode, is
just a plain dictionary.
And so the type of [INAUDIBLE] that you've got the same
convenience as Python for decoding arbitrary XML
structure that you also get access to because you define
exactly what you want to decode.
And it's not two concrete types that you have defined in
your application.
Whereas in Python, what you will get, we'll see now.
It will not be more complicated, but it will be
less [INAUDIBLE].
Because what you will get back from a general decoder XML
function will be just a Python dictionary.
Whereas in Go, you get proven types that you have defined.
ANDREW: So does that mean that when you're using the Python
dictionary you would need to test for the presence of
various keys?
Whereas in Go, the data types, because the fields are always
present in values of those types, you don't
need to do all that?
JOHAN EUPHROSINE: Basically, it allows you to address
[INAUDIBLE] or XML and be sure that they are there.
Whereas in Python, you are not sure what is in the dictionary
[INAUDIBLE].
AMY: Just as a Go novice, that's one thing
I like about it.
The strict typing, but the easy definition, so it doesn't
have all the syntactic overhead of
something like Java.
JOHAN EUPHROSINE: I think it's very [INAUDIBLE] that you
could pass an XML that's in your line and just annotate
your type just with simple annotation binding a field, a
strict field to XML.
There is no syntax you could write for something which is
not triggered.
I mean, like data binding is not a triggered operation.
I find the solution that Go uses is very convenient.
ANDREW: There's also one other nice thing about it, which is
that the XML decoder will only decode and store those fields
that you actually have present in your Go data type.
So if you're decoding a really large XML stream, you won't
have to load all that stuff into memory before
discarding it again.
You can just only take out the fields you're actually
interested in.
JOHAN EUPHROSINE: Yeah.
Whereas when you write for Python, generally the Decode
function will decode all the fields.
You will have to manually write to--
I mean, either you do the parsing yourself using some
kind of reader and then you can selectively get what you
want, but then your parsing for this doubles.
Or if you use a generic decode function, you would just get
an enormous [INAUDIBLE] if you have an enormous string.
AMY: As Andrew said, I suspect you're getting to the really
cool stuff in just a minute here.
JOHAN EUPHROSINE: Actually, just the same with JSON,
though we do exactly the same with Programming Reddits.
And so Reddits APIs have a JSON file.
And actually, it's both an access file and some JSON
file, but the RSS file structure is quite messed up.
So you can't access the link of the element, because it's
encoded to see that inside the description.
So for being able to easily pass title and links
programmatically of Programming Reddits, you need
to use the JSON API.
For that, we'll just import encoding JSON, just like we
imported encoding XML before.
We'll define a new Handle, which is called "proggit."
There is a URL slash proggit.
And we'll map JSON to Go type, just like we've
done before with XML.
So the structure of the JSON feed is a bit complicated for
what it is.
But it's like this.
So you've got the data element, which has a children
attribute, with a collection of children element.
Each of these trigger an element also of the data
attributes, which finally adds a title and a URL.
And so we'll just define Go type just as before.
So the range field is a data element.
And so you see here that we don't have any annotation
because what I find in Go is that if you don't define an
annotation, the decode function will default on
passing the attributes that correspond to
your property name.
So clearly we know that it needs to get better attributes
because we've defined a property in your structure
which is named data.
So a Reddit feed data is a collection of items.
And so we have a Reddits feed item type, which will match to
the JSON children attributes.
And so here, you can see that we have put an annotation,
because the name of our property is different from the
name of the attribute.
And then each Reddit feed thing will be a data item here
just to capture what is in the attribute data.
And the item structure will just be the same structure
that we have been using before for the [INAUDIBLE].
So here we see that we are two hierarchy types that shows the
same leaf type elements which is item.
So we'll be about to decode Hacker News and Programming
Reddits using two different functions, and we will get the
same item types back from the Go function.
So here, that is how we get [INAUDIBLE] on
JSON streaming Go.
So it's quite similar to what we've seen before with XML.
The only difference is that we instantiate a new JSON decoder
instead of instantiating an XML decoder.
We use a Reddit feed type instead of using the Hacker
News feed type.
We can decode.
In order to return a collection of
item, we have to--
it writes--
because what we get back from the decode function is a
Reddit field, which is a Reddit feed data, which is a
collection of Reddit feed item.
And what our function returns is a collection of item.
So we need to instantiate a collection of item.
So you do that in Go by using the Make key word, which
allows you to instantiate a slice of item.
And you can specify a LAN, events, and the capacity.
You know we know the LANs in advance, so we can say that we
want to instantiate as many items that we have--
Reddit feed item, you know, in the Reddit feed data.
And so we just integrate an old item and fill the new
slide that we have just created.
And so in the end, we get a slice of item
back from this function.
What's left is just that we need to print it.
So as before, we just set the Content-Type and iterate from
what we get back from the proggit item function and
point it to the response.
So here you can see that we just printed the top items
that are in Programming Reddits--
the title and the URL on the right.
AMY: And Proppy?
JOHAN EUPHROSINE: Yeah?
AMY: Since people might not be able to see that output very
well and just might be interested in general, I think
that you have the code also on code.google
somewhere, don't you?
JOHAN EUPHROSINE: Yeah, at the end of the presentation, there
will be a link to the code.
AMY: OK, great.
JOHAN EUPHROSINE: So now we need to print both, because we
are printing Hacker News items,
Programming Reddit item.
And now we want to print both on the response.
And so since we can just call our hackernews item function,
call our Programming Reddits item function, get the item
back, And just iterate on each of them and
print them in the response.
And so we'll first print the Hacker News item, and then
print the Programming Reddit item.
And here we can see that we actually printed both.
And you can see, I added some [INAUDIBLE] statement in the
code before in order to check the latency.
So we see that it took like 260 milliseconds to fetch the
item from Hacker News.
It took like 100 milliseconds to fetch
the item from proggit.
To print both of them--, like the latency of the [INAUDIBLE]
function, which was Progginator, it's just the
same as the latency of Hacker News and proggit.
So it means that if I can use a slow, like we won't be able
to print anything before I can use it as Handle.
And also, we'll just send it to latency of both URL fetch.
And so what we need to do now to be more efficient is to
make it concurrent.
So it's just like the same code that we've seen before,
we just added a few keywords.
So we are using the Go [INAUDIBLE], which is from the
goroutine, which is the [INAUDIBLE].
It will allow us to fetch a Hacker News item and a
Programming Reddit item concurrently.
So here we just--
in order to get the item back from this goroutine, we'll
create a channel.
So we create a channel.
A channel is a structure that will allows goroutines to
communicate safely between them.
So you first just figure out Go tied to a channel, and you
can send the item to a channel and read item back.
And what we will do, being that we spoke to goroutine,
that we'll each send a slice of item to the channel.
In the parent goroutine that has been spawned to
[INAUDIBLE] request, we just [INAUDIBLE]
back from the channel.
So it means that both UR shell [INAUDIBLE]
fetch concurrently has happened.
So here we just create a new chain on which [INAUDIBLE].
Here we spawn the goroutine and send the wizard, which is
a slice of item back to the channel.
Here we spawn another goroutine for Programming
Reddits and send the wizard back to the channel
Here we iterate.
We do an iteration of two, because we have two
[INAUDIBLE] to read from the channel.
Read them.
So this is a syntax for receiving
stuff from the channel.
And then we iterate up each on the slice we get back from the
channel and print them to the screen.
And here you can see exactly the same [INAUDIBLE]
as before.
And notice it's just quicker, because
here are the latencies.
So Programming Reddit takes like [INAUDIBLE]
seconds.
Hackernews takes 190 seconds.
The progginator function only takes the highest
latencies of the two.
So it means that both of our fetch calls happen
concurrently.
Since they happen concurrently, we are only
bound to the slowest one instead of being bound to the
center of the two latencies.
So are some takeaways from the talk.
The encoding package makes parsing fun again.
So we see that it's really easy to bind a Go native type
to either XML ends or Java attributes, which make parsing
really easy and serve a call.
We have seen the Go runtime is inherently concurrent.
So you can easily spawn a goroutine and make sure to
handle any operation concurrently.
And also, the Go runtime will run a Go routine each incoming
HTTP request.
And we've seen also that there is no need--
in Python and in Java, in order to do the [INAUDIBLE],
we'd have to use an async API.
Here we see that in Go, we don't need to add an async and
sync version of an API.
We just wrap the code we want to be in sync with [INAUDIBLE]
and just use a channel to get the [INAUDIBLE] back and
return a synchronous API code into something asynchronous.
And so there is some homework that you can do in order to
improve this demo.
Obviously, the same stuff gets often [INAUDIBLE]
since you've got both hackernews
and Programming Reddits.
So you can write some code to get
duplicates and also by ranking.
You can make it pretty, because it's just plain text
right now, so you can make it prettier with
templates and CSS.
You can move the fetch to happen offline instead of
happening on each user request.
So instead of doing a URL fetch on each HTTP request,
you can [INAUDIBLE]
that will do the URL fetch as a bad one and then cache it.
So when you have like thousands of people that use
the site, you don't do a URL fetch to fetch some content to
Reddit and [INAUDIBLE]
each time.
And you can go fork the messy code at this URL.
So
code.google.com/p/progginator project.
And the slides are also available in this [INAUDIBLE]
too.
So thank you.
There are some links that you can investigate if you want to
work further.
This is a doc for the Go App Engine runtime.
This is the main website for the Go [INAUDIBLE].
And there is my profile on Google+.
So if you have questions, we can do them now.
AUDIENCE: Proppy, can you hear me?
JOHAN EUPHROSINE: Yeah.
AUDIENCE: Just a quick question.
You were using [INAUDIBLE]
channel [INAUDIBLE]
when you're collecting the item [INAUDIBLE]
concurrently.
You would be passing directly the channel [INAUDIBLE].
passing them to your template.
JOHAN EUPHROSINE: I'm sorry--
AUDIENCE: Yeah.
JOHAN EUPHROSINE: [INAUDIBLE].
I couldn't really hear the question.
Can you try it a little bit more slowly?
[INAUDIBLE].
AUDIENCE: I'm in the chat.
JOHAN EUPHROSINE: Yeah, just type through the chat.
It would be simpler.
AMY: Yeah, I can read it out if you like.
[TYPING]
JOHAN EUPHROSINE: So the question is, if you were using
templates, would you patch them directly to the templates
or collect an item and pass in those to the templates?
So I think I would do the latter.
So what I would do is that I would--
because what I get back from the channel is not actually
the usual item.
I get a slice of item from the channel.
So what I would do is with the main Go routine, I would
collect the item from the channel, the slice of item
from the channel, and just print them out by template by
giving it the slice of item [INAUDIBLE].
That's really [INAUDIBLE]
different perspective of this.
ANDREW: With the way it's currently designed, then,
yeah, you probably would do that.
But it is possible from within a template to range over a
channel in the same way that you can range over a channel
in novel Go code.
And that's particularly useful if you have some code that's
generating values, like a large stream of them, and then
you want to generate a particularly large template.
You can have your generator and your template being--
you have the values being generated and the template
being constructed concurrently without having to load your
entire data into memory, which is a really nice property.
But in this particular instance, you're already
loading all of the items into memory immediately when you do
the JSON and XML decodes.
So there's no real advantage to streaming them into the
into the template itself.
You might as well just collect them, and arrange them before
passing them into the template.
And that's what I would do usually as well.
JOHAN EUPHROSINE: Also when we pass an item, a slice in the
channel it's not-- it doesn't copy them [INAUDIBLE].
It's just a reference to the same slice of this, right?
ANDREW: Yep.
JOHAN EUPHROSINE: So we aren't duplicating the slice content
in multiple goroutines.
ANDREW: I was going to say, in this case, are they items, are
they values, or are they pointers to items?
It looks like they're items themselves.
JOHAN EUPHROSINE: Yeah, they're items themselves, but
when you pass it to a channel my understanding is that when
you enter a slice of item to a channel, you don't copy the
individual elements, right?
ANDREW: Yes, that's correct.
I mean, when you pass a slice around, you're passing a
reference to the underlying data.
But if you wanted to sort or de-duplicate those items and
interleaf the ones from proggit and the ones from
Hacker News together, then you might consider
using a pointer type.
So a slice of pointers to items instead of a slice of
items, and you'd have some small saving there.
But the actual item struct is very small, because it
consists of some string values.
And string values in Go are reference types as well.
And so there's very little copying going on there.
I mean, each item is probably only
about 64 bytes or something.
JOHAN EUPHROSINE: So very quickly, take a look if
there's any questions on Google+ or on the [INAUDIBLE].
AMY: OK, I have a question for you, Proppy, if there are no
other questions.
I have to take a quick look first.
ANDREW: Well, there is one question on the moderator,
which is an App Engine question.
And it's from Jurka Danyik from the Czech Republic
saying, I don't want my app to depend on App Engine too much.
I'm afraid of the vendor locking issue.
How hard is it to build an app in Go that runs on App Engine,
and if needed, can be moved to my private web server?
JOHAN EUPHROSINE: I think that actually David can comment
about this, because he recently implemented something
in the Go build that dealt with it.
DAVE: It'd be pretty easy to write a Go App Engine app that
has minimal dependencies on App Engine itself.
For example, the Go website itself, golang.org, is built
by an App Engine app.
But that App Engine app is almost completely just Go doc,
which is a standard Go program that you can build and compile
and run on your own machine and ships with the standard Go
distribution.
All that has is a very small, little [INAUDIBLE]
file that [INAUDIBLE].
And other than that, it's just a regular, like I said,
[INAUDIBLE] design.
The Go runtime on App Engine is pretty permissive for
allowing you to write something that's independent
of App Engine.
ANDREW: So to learn to write an app like this, this is
actually very portable, because the HTTP package is
well integrated with Go on App Engine.
So like what Dave just said, if you write just a straight
web app that doesn't really talk to much of [INAUDIBLE],
you can basically just use one in one place or the other.
The one that we're using here is URL fetch.
And if you look at the-- is it on this slide?
Proppy, can you go to a slide which has the [INAUDIBLE]
urlfetch client on it.
I think that had it.
So if you notice on the first line of this function after
the declaration, the URL fetch client, that variable client
is actually just an HTTP client, the same type of HTTP
client you would use in a standalone Go program as well.
So the URL fetch client just implements the same
interfaces.
And you can use anything that expects those interfaces,
which is basically any Go package that uses HTTP.
So we tried really hard in creating all of the Go App
Engine APIs to use a lot of the standard Go interfaces so
that it's really easy to--
I use the Go standard library and external libraries with
the App Engine APIs and also to decouple your app entirely
from App Engine.
With that said, if you write an App Engine app that depends
heavily on the task infrastructure and the App
Engine data store, those are really, really rich APIs.
And that's one of the real value adds of the App Engine
platform, is that you get these really, really scalable,
reliable systems.
That you don't get free.
And it would be a little bit more difficult to divorce
yourself from that.
JOHAN EUPHROSINE: It's interesting to note that there
is a project called App Appscale that implements the
Go runtime.
It allows you to run basically APIs tablet that [INAUDIBLE]
database or [INAUDIBLE] software that will just
provide you the same SPI that you have on App Engine, just
with different back-end issues, like MongoDB,
[INAUDIBLE].
And also I wanted to--
maybe David can you tell us a bit about the build tag, the
App Engine build tag.
Because I think that you can easily design your apps so you
have the App Engine specific parts that are as efficient as
with App Engine buildout.
And so you can still use the regular Go build to build your
stuff without the App Engine specifics, right?
DAVE: I'm not entirely sure what you're asking me.
[INAUDIBLE]
that you fill in with an implementation that you're
using the App Engine APIs and--
JOHAN EUPHROSINE: No, I was thinking like, for example,
Andrew was saying that your URL fetch module uses the same
JFS as the regular HTTP client.
DAVE: Yeah, [INAUDIBLE].
JOHAN EUPHROSINE: If you write your App Engine specific code
and just [INAUDIBLE]
it with the App Engine name tag, can you make sure that
the Go To when it builds your application doesn't build the
pieces specific to App Engine?
DAVE: Yeah.
So just in the same way as you could say some platform
depended on [INAUDIBLE] or that you had some who would
only work on Linux or some who will only work on Mac or some
who would only work on Windows, you can add a little
annotation at the top of your source files, and then Go To
will only build those when it's on that platform.
The same thing with App Engine.
So if you have a build tag at the top of your file that says
this file requires App Engine or App Engine apps
[INAUDIBLE].
JOHAN EUPHROSINE: OK, so yeah, I think that's neat that there
is a super build team into the Go To number to get one
application that can get more than one platform.
DAVE: Yeah.
AMY: So let me ask you a question, Proppy.
And this is also directed to Andrew and Dave, if you want
to answer it.
So the Go routines and channels are really cool.
And it's sort of a philosophical departure from
what people might be used to or might think of as your
regular thread program if you're a Java programmer.
And it seems like it lends itself less to getting into
trouble with that kind of programming.
Maybe you want to comment a little more on that?
ANDREW: Well, I mean, if you consider Proppy's example of
performing these two calls in parallel and then having a
rendezvous and collecting the results, using a traditional
kind of semaphore approach, you would probably use a white
group or something like that.
Generally, there's just a lot more boilerplate involved in
setting up the channels and setting up the locks.
And then there can be a lot more--
basically what you're doing is you're
talking around the problem.
You're creating these kind of [INAUDIBLE].
JOHAN EUPHROSINE: So it seems they are just frozen for me.
Is it the same for--
OK, so you were frozen.
AMY: Yeah, we're back, but I think we need to start over
with what Andrew was saying.
ANDREW: In essence what I'm saying is that in Go, to make
something run another thread is [INAUDIBLE]
in the space.
In pretty much any other traditional threading
environment, there's a lot more involved in
setting up a thread.
And similarly, to communicate between threads in the
traditional method, you have some sort of
semaphore, like a lock.
And then you have the data that you want to communicate,
and they're two separate things.
In Go they're combined into the same thing.
You have a channel, and the channel is both a signal--
it's synchronization--
and it is the message itself.
It's the data.
And so it's a lot less error prone, particularly once the
system becomes more complex.
And so I think it's a pretty clear win, if you're doing any
kind of [INAUDIBLE] software.
JOHAN EUPHROSINE: One of the mantras of the Go [INAUDIBLE]
is don't communicate by sharing, but share by
communicating.
I think that it's fitting.
It's also really useful.
I mean, the way the App Engine-- maybe David can
correct me, but the way that App Engine runtime is designed
is that it will spawn one Go routine for each information
you request.
It will not run more than one Go Looking at a time.
But if one Go looking is doing IO, it can add an addition to
another Go To.
And since most of what App Engine apps are doing is to
make APC code and API code, that's really a strong win for
App Engine.
Even if it's single threaded, it's on [INAUDIBLE]
operation concurrently.
ANDREW: And Go is easily the most lightweight of the three
App Engine runtimes as well.
So in terms of squeezing CPU time out of your instances, I
think it's pretty good for that, too.
Does anybody else that's in the Hangout have questions
that they'd like to ask about the talk or about App Engine
or about Go?
AMY: Are you still on the IRC channel?
JOHAN EUPHROSINE: Yeah, I've muted a few people, so maybe I
can unmute them.
And so does anybody have a question?
No?
AMY: There's Chris.
JOHAN EUPHROSINE: Oh, Chris is here.
Hey, Chris.
AMY: Any questions about [INAUDIBLE]?
JOHAN EUPHROSINE: I do.
DAVE: Does the mic work?
JOHAN EUPHROSINE: His mic is broken.
So he may have a question on chat.
He says, I like the example where multiple wizards come
from Hacker News and Reddit at the same time.
Is it possible to run on desktop queries completely?
DAVE: Yes.
Very easy.
JOHAN EUPHROSINE: You just have to wrap your API code
into Go routine and run concurrently.
ANDREW: In essence, yeah.
But with the data store, though, you have to be aware
that it won't necessarily buy you a lot.
It depends what you're doing, particularly if you're doing
transactions within entity groups.
If you try and conduct two transactions on same data at
same time, or even on data that's in the same entity
group, you probably won't see a big win over just doing it
sequentially.
Because instead of serializing in the client, it'll just be
serializing it inside the data store.
DAVE: He could do it probably with a URL fetch.
You're rendering--
well, you could do fetching your [INAUDIBLE]
from the data store at the same time as doing a URL fetch
to that weather service because The weather in Sydney
[INAUDIBLE].
You would be doing all that at once, very easily.
JOHAN EUPHROSINE: I don't know about the specifics about the
way the data store--
the smallest API layer of the API code [INAUDIBLE].
But I know that for Python-- maybe David can confirm, but I
know that for Python when you are doing an emergency Get on
each [INAUDIBLE], it will actually do much better
[INAUDIBLE].
I don't know if it's doing the same for Go.
But you have to realize that there is that candy, that
extra level of concurrency that sometimes is introduced
on the library layer, so on the SDK layer.
So for me, it can look like just an API code, but the user
will be [INAUDIBLE].
And also there is another layer of concurrency happening
on the south side.
So when the data store back and receive your request, it
can decide to go and fetch [INAUDIBLE]
concurrently as well.
AMY: We had someone typing in the chat window.
In app.yaml for Go Runtime, we expect to find
script_goapp as the--
ANDREW: --as the main handler.
So what is the magic behind that?
So essentially when we designed the Go App Engine
SDK, we based it on the Python SDK.
And so the Python SDK uses an applet YAML file to define
[INAUDIBLE].
And in Python then, you actually specify the
[INAUDIBLE], and then you have a script directive that says
which Python script is actually going
to handle this request.
But in Go, we don't run multiple Go programs for
multiple requests.
We just run a single instance of your Go app.
And then all of the HTTP requests that are to be
handled by the Go app are sent to that single app, no matter
how many handles you have to find.
So this script calling _go_app signifies that this is a
handler that should be handled by the app.
And so you can't have separate Go apps that handle different
parts of your app.
But you can just write totally independent packages that
handle various handlers independently.
And they can effectively be independent programs.
But on the server side, you must understand that they're
actually built into the same binary, and
they're executed together.
So it's a slight departure from the
way it works in Python.
JOHAN EUPHROSINE: I think that you can--
you handle most of the routine in your Go application as
opposed in Python where you enter some of the routine at
the channel and some of the routine in your Python
application.
It's actually a cleaner design, because you actually
only have one place to put your dynamic routine, whereas
in Python, you can decide to put them in two places.
Sometimes it's confusing for users as well.
I would like add to what Andrew says.
You can add back ends that are different Go apps, That?
Interact some or with your Go application with [INAUDIBLE].
So if you need to read the same application in space, if
you need to be deploy each part of the Go program, you
can either use version or you can use back end in order for
you to deploy different binary to the same application.
ANDREW: And also if you have a Python application and you
want to use Go to do something that you can't do in Python,
like if you have some number crunching or something, you
can actually deploy a Go back-end to your Python app
and communicate between the two using [INAUDIBLE], which
is actually a pretty powerful combination.
You could do the same with Java as well.
But I'd also like to ask if you can
have multiple handlers?
And the answer is, yes, you can have multiple handlers.
But the point that Proppy was making is that your app
channel can basically just have a catch-all expression in
the handler and then hand off all of the routing requests to
the Go app itself.
So you just have your handle clauses in the Go app handling
the [INAUDIBLE] that you want
DAVE: In fact, Proppy's example for the tool has at
least three handlers.
JOHAN EUPHROSINE: So any more questions?
Otherwise, I guess we [INAUDIBLE].
DAVE: So, to an actual binary, yeah.
JOHAN EUPHROSINE: He's talking binary.
So Alex says that he got it like we are combining the app
to a sort of binary, but that's actually a binary.
DAVE: Yeah.
It's the real program.
It runs in the HC.
JOHAN EUPHROSINE: And the nice side effect is that it's
really fast to run.
So the Go instant start-up time is really one of the
fastest of all the App Engine runtime, because it only needs
to read a single file in order to start your application.
ANDREW: Yeah, in contrast to Python, which has to actually
interpret your Python code and fire up a Python interpreter,
or the JVM, which actually has to load a JVM.
And so if your app sees a sudden spike of traffic, I'd
go out and respond really, really quickly, because it
takes hundredths of a second to fire up a go-out.
It really is pretty impressive.
JOHAN EUPHROSINE: Yeah, I have a question for David.
So you know that when you start a Go routine in App
Engine, you can only do useful things in the
window of the request.
So if you're outside of the request window, you can
already interact with the API.
You can still have global channel running in the
background in your application, but there
wouldn't be a bug to issue an new API code, right?
DAVE: Right.
Yup.
JOHAN EUPHROSINE: I was wondering if there is support
for [INAUDIBLE]
in the Python Java runtime, as there was a new concept
introduced which is called [INAUDIBLE].
That's on YouTube defined to pull threads that span across
the request window.
But it's only for the back end.
And I was wondering if there is the same thing which in
planned with Go?
So we need to explain all the things that can--
just one Go To that can interact with API and not tied
to an HTTP request.
DAVE: So there's two modes of operations for back ends.
There's a serving back end, which serves requests.
You know, requests come in.
It will handle it.
It will generate a response.
And then finish up that request.
But there's also--
I don't remember the terminology--
lonely back ends, processing back ends.
And in that case, what happens is that the Go instance will
start, and the App Engine infrastructure will say that a
request to a URL, something like _ah/*.
Now, if the back end doesn't return from that, then that
back end string is a long running processing back end,
which means that you have effectively a long running
request that can last for minutes, hours, days, weeks.
And so during that time, you can make API calls.
If you construct an App Engine context from that request that
you received to _ah/*. "A," "H," So even if they could get
the same thing where you can have something long running
for a long time, but make API calls.
JOHAN EUPHROSINE: So you just have to use the customer as
the context when you get the warm-up and just reuse the
same context forever.
DAVE: Yeah, and not return from that initial request.
JOHAN EUPHROSINE: OK.
ANDREW: Yeah, in effect that becomes your main.
Like if you're running a standalone function, then that
main-- that start handler is just like your main function.
JOHAN EUPHROSINE: Yeah, and if [INAUDIBLE] serving the back
end is doing IO, if this long running back end is doing IO,
for example, like it's looking at a channel or like looking
at API code, does that mean it can answer incoming HTTP
requests as well?
DAVE: No.
If the back end doesn't return from the [INAUDIBLE]
start request, it won't be sending me more requests.
It won't be building in that respect.
JOHAN EUPHROSINE: OK.
AMY: OK.
Well, I think we're at the top of the hour so, as they say in
radio, so if we have no more last minute questions, thanks
everyone very much for joining us or for watching.
ANDREW: And thanks, Proppy, for writing and
delivering the talk.
AMY: Thanks very much, Proppy.
See you guys next time.