
Space Monkey dumps Python for Go - jtolds
https://www.spacemonkey.com/blog/posts/go-space-monkey
======
chimeracoder
This article doesn't address one of the biggest benefits I've noticed in
switching from Python to Go.

I've been using Go for almost two years now. Like OP, I am/was primarily a
Python developer. Like OP, my first Go project was a time-sensitive rewrite[0]
of a project from Python (tornado) to Go.

Even though I was an experienced Python developer, the Go rewrite was
marginally (~20%) faster[1]. But the real benefit came from the _subsequent_
development - refactoring, rearchitecting, and maintaining the project on an
ongoing basis. Go was designed to make it easy to scale the maintenance[2] of
software, and on this one axis, it absolutely blows every other language and
environment I've used out of the water.

For a fresh project, I'd say Go is about 10% slower to write than the
equivalent Python[3] for the average case. But the time/cost savings are
_very_ quick to come thereafter.

[0] I would absolutely not recommend doing time-sensitive rewrites in general,
but that decision was a separate matter.

[1] Some of this is due to the nature of rewrites in general, but the fact
that it wasn't slower to use a language I'd never used before says something
about the language.

[2] Scaling software development as teams grow is _very_ different from
scaling software as users grow.

[3] Assuming comparable familiarity with both languages, which is rarely the
case, of course

~~~
nostrademons
I'm curious, how does it compare to Java with a good IDE (eg. Eclipse or
IntelliJ)?

One thing I really missed when I abandoned the Java world and went to
C++/Python was the refactoring and formatting tools available in the IDE. I
could set it up so it'd auto-format my code on save, so that I could rename
methods with a single keystroke, so that I could pull out classes or add
getters/setters, so that I could add parameters, etc. I know Go supports some
of that through gofmt and go fix, but I'm curious if anyone is both an
experienced Java dev and an experienced Go dev and can compare the continued
maintenance costs of the two.

BTW, I would put the productivity premium of Go over Python at about 50%-2x,
not 10%. I did a mid-size (~6 man-months, though much of that time went into
interactions with other teams) green-field prototype in Go at Google, and
found myself really missing constructs like list comprehensions, dynamic
typing, strong support for literal data, ability to treat user-defined types
just like the built-ins, etc. I do think you'll make some of that back in
continued maintenance - I actually really enjoyed working with Go - but I
didn't experience the claims of "Go is just as good as Python for
prototyping", as someone with a fair amount of Python experience.

~~~
jbooth
Experienced Java and Go dev here.

On formatting, gofmt is awesome. There's an IDE called LiteIDE which
automatically calls gofmt for you, or you can just run it yourself whenever.
Additionally, because there's deliberately no room to customize gofmt, you
don't have to spend time in pointless meetings when "that guy" decides it's
time to rewrite your company eclipse templates and argue over all the
minutiae.

As far as refactoring, nobody's built an IDE integration that comes close to
eclipse/IDEA for that as far as I know. It's totally doable in Go, in a way
that it wouldn't be for Python (yay types), but I don't think anyone's done
it. On the upside, doing it manually is less painful than it would be in
typical Java code, due to type inference and having less code to begin with.

~~~
kasey_junk
gofmt is the single biggest feature of Go that might make me try it out. Such
a great idea, I wish every language would adopt it.

~~~
to3m
If you use C# in Visual Studio, you can press Ctrl+K, Ctrl+D to have the
entire document reformatted. Surprisingly few people seem to know about this,
judging by how often I've found myself using this on other people's source
files and had everything shift around. (Or maybe I'm just unusual and
everybody else has just played with the settings.)

The reformatting is actually quite aggressive (it will add/remove blanks and
move braces and bits of code around), and so does a good job of keeping
everybody's code looking consistent. The Visual Studio text editing
functionality only occasionally reaches even the lofty heights of "pretty
good", but I do think the document reformatting actually even exceeds that.

(Shame the settings are are per-user rather than per-project, but there you
go. It wouldn't be Visual Studio if they didn't manage to fuck something up at
the last moment.)

~~~
dikei
Every decent IDEs have a code formater, but not everyone uses the same IDE so
its usefulness is limited. On the other hand, gofmt comes with the platform
and make it easy to enforce a common standard between developers.

~~~
ufo
That said, I think that in C#'s specific case most developers should be using
Visual Studio.

~~~
sparkie
The default Visual Studio formatting sucks - wasted lines for opening braces
when we have limited vertical real estate. Visual Studio should support per-
project, or per-solution formatting configurations, which can be placed into
the source code repository to ensure everyone on the team is using the same
settings - MonoDevelop already does this and it's really useful for switching
between projects which use different formats.

------
sandGorgon
_We rewrote Twisted Deferred handling to be 30% faster. We optimized the
Twisted Reactor event loop to not only do less constant work, but to prefer
incoming I /O.

...We spent long nights poring over profiling readouts and traces, wrote our
own monitoring system, and wrote our own benchmarking tools

... We enabled cgroups on our Python process to tightly control memory usage
and swap contention without requiring a different Python memory allocator
scheme. _

This is very interesting for the rest of the Python/Twisted community - now
that they are not using this (and so is'nt part of the secret sauce), I wonder
if they are willing to push this out as a patch/blog post ?

~~~
jtolds
We're planning on open sourcing a bunch of stuff. We'll have some follow up
posts.

~~~
sandGorgon
thanks !

really look forward to this..

------
sigil
It sounds like the cost of context switching between these very different
workloads (crypto, disk I/O, network I/O, protocol buffer parsing and
formatting) could be improved in Twisted.

Any idea where the overhead comes from? Twisted, or the Python interpreter
itself? Is this a GIL performance issue? Or perhaps even lower -- something
here is really hostile to CPU cache?

I realize this is a matter of taste, but my favorite async framework is still
the kernel. Write small programs that do one thing well (and thus have pretty
uniform workloads) and then let the kernel balance resource usage.

 _After continuing to hit walls with the standard Python Protocol Buffer
library, we wrote our own that was 5x faster than the barely-documented C++
Python Protocol Buffer compiled module support._

Ugh yeah, the standard Python protobuf library is pure python and horribly
slow. And it requires code generation -- in a dynamic language! The C++ one is
faster, but also requires code generation and is just nasty to work with.

Not that this matters much to you at this point, but I have a small C/Python
protobuf library that's 10x faster than the standard Python protobuf:
[https://github.com/acg/lwpb](https://github.com/acg/lwpb)

PS. I see you're in SLC area -- me too. We should talk tech shop in person
sometime!

~~~
jtolds
Hi! Yes, you should totally swing by. Shoot us an email :)

I think the sort of performance issues we were hitting were honestly related
to just Python runtime overhead. A Python function call is actually really
expensive, and with Twisted Deferred handling, it's really hard to eliminate
the massive amount of function calls each I/O event does.

We just had a really slow CPU so we did our best to eliminate as many Python
function calls in hotspots as possible, but yeah that was challenging.

~~~
sigil
_A Python function call is actually really expensive, and with Twisted
Deferred handling, it 's really hard to eliminate the massive amount of
function calls each I/O event does._

Ah, makes total sense. Any particular reason you chose to use Twisted in a
hardware appliance? Is there a web interface that's supposed to be super
responsive?

~~~
jtolds
The main codebase actually started out targeting desktop-class hardware, but
the poor uptime of user's work machines (now laptops, soon tablets) actually
made our business model not work, hence the dedicated hardware.

------
cgag
I like seeing people embrace static typing, but it makes me sad that it's a
language where you can't even write a container (a map/dictionry/linked-
list/etc) without giving up type safety.

I recognize that Golang is filling a gap, letting people get static typing
without having to learn much new stuff, and there's value in that, but I think
Go enthusiasts should read these great posts by Tikhon Jelvis with an open
mind:

[https://www.quora.com/Googles-programming-language-Go-
seems-...](https://www.quora.com/Googles-programming-language-Go-seems-to-be-
the-most-modern-and-well-featured-language-in-existence-today-Is-that-the-
case-or-are-there-major-drawbacks-that-Im-not-seeing)

[https://www.quora.com/Go-programming-language/Do-you-feel-
th...](https://www.quora.com/Go-programming-language/Do-you-feel-that-golang-
is-ugly)

~~~
burntsushi
Quite frankly, those articles are absolutely terrible. Firstly, it's clear
that the author assumes there exists _some correct_ way to design a language.
(I reject that.) Secondly, the author never acknowledges any of the trade offs
that come from adding additional features to a language. (Hint: one of those
trade offs is... there are more features!)

This isn't a revolutionary thought. More compile time safety _generally_ means
more complexity in the type system. We, as programmers, must decide when,
where and how much we're willing to pay for that type safety.

You can go balls-to-the-wall with Idris or Agda or ATS and encode a whole mess
of things directly into your types. Maybe you can completely remove out-of-
bounds errors! Surely, this is better than the _alternative_ , which admits
less safety.

This isn't a fair comparison because all three of those languages are
ridiculously hard to use for practical things. (Well, it's hard for me,
anyway.)

Then there are other, more practical languages like Rust, Java, Haskell,
OCaml, etc., that all provide a helluva lot more compile time type safety than
Go does. (Or, to be precise, a lot more expressive power with respect to
compile time safe polymorphism.) Some of the languages go even further; Rust
eliminates data races and Haskell isolates "side effects" with monads.

All of these things are wonderful, because we get a lot more guarantees about
ways in which our program cannot fail once it's compiled. But they _aren 't
free_. They come with a cost. Typically the cost is in greater language
complexity. The programmer must write code that the compiler accepts. If
you're in that language's wheelhouse, maybe the complexity isn't so bad. But
when you want to write a program that isn't easily accepted by the compiler,
you run into complexity. Maybe it's not that bad---maybe you just need to
figure out how to write a monad transformer. Or maybe you just need to think a
bit more carefully about the lifetime of a borrowed pointer. But other times,
you need type families and multi-parameter type classes before you can make an
unboxed vector with your own type:
[http://hackage.haskell.org/package/vector-0.10.9.1/docs/Data...](http://hackage.haskell.org/package/vector-0.10.9.1/docs/Data-
Vector-Unboxed.html) \--- The safety is great, but dammit, you're going to pay
for it.

On some days and for some projects, I'm more than happy to pay the price for
safety. It is immensely satisfying to write a program and be able to make all
sorts of claims about its safety. (I just wrote a regexp implementation in
Rust. Guaranteed no memory errors. No GC. Totally type safe. It's awesome.)
But other times, I don't feel like paying the cost.

And _that 's_ OK. It's not sad. It's not "ugly." It's a legitimate and
reasonable choice given a trade off.

Saying a language is "badly designed" just because it didn't include _your_
preferred set of features is bad juju IMO.

~~~
fauigerzigerk
I agree with much of what you said, but an expressive type system isn't just a
safety mechanism. It's also a tool to write fast code productively. Without
compile time metaprogramming some things will always be either extremely
resource hungry or extremely repetitive.

It's absolutely true that there is always a trade-off. Metaprogramming makes
code more difficult to understand and hence more prone to certain types of
errors. That's true for runtime metaprogramming as well though.

So if the lack of generics leads to an overuse of reflection (or worse to
custom code generators) then the complexity you avoided in the language is re-
introduced through the backdoor.

At the end of the day I think it's about the culture that gets established
around a language. Go's creators are trying really hard to socially engineer a
culture of simplicity, and that's laudable. But it reminds me of the early
days of Java even though the Go community would rather have me think of C.

The big difference: C had compile time metaprogramming from the beginning,
Java did not. Look which one turned out to be the simpler ecosystem in the
end.

------
wting
I think people are rediscovering the benefits of static typing for performance
and correctness reasons. The latest generation of statically typed
languages[0] all have some level of type inferencing which helps.

If Python is fast enough for you, it’s a fantastic language. The problem is
once performance or codebase demands scale, dynamic typing rears its ugly head
and there are no simple solutions. At work we sidestep this issue by writing a
plethora of tests, but now dynamic typing productivity gains are offset and we
spin up a lot of AWS instances for performance.

[0] Go, Rust, Scala. Haskell and OCaml have had it for a while.

~~~
femngi
C++ isn't exactly a new language but has also had type inference for a few
years. I think people still think of C++ as that dusty old thing in the corner
and forget that it is actually capable of a lot of the things users of these
new languages get excited about.

~~~
masklinn
C++'s auto is younger than most of these languages (let alone than Haskell or
MLs), to say nothing of actual tooling support.

~~~
dilap
gcc has had auto under a different name (typeof) for years and years, though i
don't think it got much use outside of programming competitions.

------
hyp0
Wouldn't java be the natural rewrite, for performance speed up? Java is betwen
Python and C, in terms of ease-of-use and performance. They mention a C
rewrite, but not a java one...

I guess the concept here is that Go is between Python and Java: (much of) the
ease of use of Python + (much of) the performance of Java. The type system
literally straddles the dynamic and static.

[ I also detect an enthusiasm for cool, new tech for its own sake (despite
risks and cost, or whether it's actually better or not - _hell let 's find
out!_) ]

~~~
untothebreach
Since they are targeting an embedded ARM system, maybe they had concerns about
running the JVM on such constrained hardware?

~~~
pjmlp
You mean like these?

[https://www.aicas.com/cms/en/JamaicaVM](https://www.aicas.com/cms/en/JamaicaVM)

------
melling
"So in the bottom of the ninth, we decided to transliterate our 90k lines of
Python directly to Go, line by line.

It took us about 4 weeks."

How many people worked on the project? What's the build time on a program of
this size?

~~~
yukichan
I wonder how many lines of code they ended up with afterward, although
admittedly lines of code is a pretty silly metric. I think it is useful in
orders of magnitude when describing the size of a project, 100 lines, 1,000
lines, 10,000 lines, 100,000 lines all speak volumes about effort. So I guess
what I'm wondering if you got about a roughly similar sized code base or
significant change difference?

~~~
jtolds
EDIT: fixed my calculations again.

Without tests but with our supporting libraries, our codebase was 36784 lines
of Python. Those same lines became 41717 lines of Go.

Counting lines of code is hard.

------
TD-Linux
I wrote some Python to run on an OpenWRT (MIPS-based, 400MHz) router that
interfaced with an Xbee radio and ran a web interface. I quickly discovered
that what I expected to be IO-bound was in fact CPU-bound - reformatting the
data and all the related text operations were fast enough after optimization,
but only by a hair.

Our solution was to switch to a dedicated ARM board (beaglebone) attached to
the router. But I'm definitely going to take a look at using a compiled
language now, as the codebase is still very small.

------
andybak
I've got a completely data-free feeling that Ruby people hitting performance
bottlenecks seem to reach for node whilst Python people have a tendency to
look at Go.

Does anyone else think that this rings true? And if so - is it a cultural
thing?

~~~
chc
My impression is that people writing Web interfaces reach for Node while
people writing CPU-heavy programs reach for Go. It so happens that Ruby people
are more often writing simple Web apps while Python is somewhat more likely to
be used for more computationally intensive tasks, but I think that's about as
far as the correlation goes.

------
jessaustin
_After all of this optimization, we got up to 1.2 MB /s._

Ouch. That was a lot of work for 0.2 MB/s. The next 2.8 MB/s was _also_ a lot
of work, but it seems conceptually more straightforward.

~~~
wspeirs
Switching to Go though they were able to get 4MB/s. Even though they claimed
to do "line-by-line" translation, I wonder how much of that speed-up was
language/libraries vs rearchitecting.

~~~
robotresearcher
Unless there is some reason to disbelieve the line-by-line claim, can't we
assume it's all due to the more performant implementation?

Python is a joy when it's fast enough, but it's not surprising that it isn't
good at throughput on small devices.

~~~
wspeirs
I didn't mean to imply they were lying in the post, more that it's probably
hard to do a line-by-line translation from Python to Go. The nature of having
to convert to things like channels in Go might help to re-architect the
program even at a micro-level.

------
wisty
That's actually kind of shocking. I thought it would take way more work to
port from Python to Go, and a 400% speedup is way less than I'd have expected
(though this is string handling, and the Python was already brutally optimised
with C modules where it counted).

~~~
jtolds
We're I/O bound now (as we should have been to begin with), so speedup isn't
the linear function you might expect here.

------
phaedryx
I'm curious what the memory usage was like before and after.

~~~
jtolds
Doh, I totally should have mentioned that, cause yeah that was big too. We
went from about 80-95mb resident memory (and our cgroups config doesn't allow
for much swap) to about 50-60mb on average, which is a metric we weren't even
trying to get lower. So, yeah, that's another win we should have mentioned.

------
dekhn
One thing to mention, since the OP talks about developing for ARM:

I was surprised recently: first that Go itself bundles a cross compiler (you
can easily download Go on x86 and compile ARM binaries with it), second that
this made developing for Raspberry Pi and similar platforms very productive,
and third that many Linux distributions have QEMU and set up binfmt
translation so ARM-compiled binaries run on x86 with no extra effort.

~~~
jtolds
The qemu binfmt extensions inside a chroot are so great.

For the uninitiated:
[https://wiki.debian.org/EmDebian/CrossDebootstrap#QEMU.2Fdeb...](https://wiki.debian.org/EmDebian/CrossDebootstrap#QEMU.2Fdebootstrap_approach)

------
dalek2point3
Can someone tell me how much control GOOG has over the development of Go? I'm
interested, but worry that is this another GOOG "open source" project that
they have a huge say in.

~~~
GhotiFish
Looks pretty open to me:

here's the current bleeding edge:
[https://code.google.com/p/go/source/browse](https://code.google.com/p/go/source/browse)

here's the issue tracker:
[https://code.google.com/p/go/issues/list](https://code.google.com/p/go/issues/list)

looks like it's being used by the dev team.

If you would like to fork the golang project, run this command:

    
    
      hg clone https://code.google.com/p/go
    

This is pretty clearly not Android.

~~~
ansible
Note also that Googlers have stated that they use the public version like
everyone else.

------
impostervt
Is anyone else getting SSL errors on the site?

~~~
jtolds
We're getting slammed :( We're spinning up a new webserver.

~~~
nkozyra
This would have never happened with Python ;)

~~~
jtolds
Our website is Apache + Python :)

~~~
nkozyra
Yeah, was tongue in cheek. I also happen to be a pretty big golang enthusiast,
anyway.

~~~
jtolds
lol, I just thought it was an amusing situation.

------
flavoie
I'm curious if they tried Cython. I've read that you can achieve up to 35%
speedup just by compiling python code, plus you can type pyx file to get near
C performance.

I never tried it, this would have been a nice use case.

~~~
jtolds
We did. We used Cython where we could, but Cython doesn't work with Twisted
(or at least inline deferreds, which holy we had everywhere), due to different
generator semantics. Edit: in fact, our internal protobuf lib was all
generated Cython. We had a code-gen inception.

------
adem
"So in the bottom of the ninth, we decided to transliterate our 90k lines of
Python directly to Go, line by line."

A question here: Is it always a practical approach to transliterate line by
line when transitioning to another language or because "Go [is] semantically
very similar to Python"?

~~~
avenger123
Usually it's too much work to do a refactor with the new language and a
conversion.

Much easier to convert first (with whatever warts the existing code base has)
then do a refactor.

So I doubt their approach had too much to do with Go per se and more with
wanting to get something out sooner rather than later.

------
jlafon
If you did a line for line transliteration, did you use any of Go's
concurrency features such goroutines or channels? I ask because I find that
when I translate a program from Python to Go that it's beneficial to structure
the program differently so that I can use goroutines.

~~~
jtolds
With Twisted (and with our threadpool worker pools), many patterns translated
directly into Goroutine usage in a much cleaner way. Where with Python we were
using our own helper libraries, Go's stdlib and the language itself were often
more than enough.

We didn't end up using channels too much. Deferreds got translated into
Futures that we wrote a small library for. Many of our Go-specific utility
classes do use channels heavily though.

------
dilap
I'm curious as to how they did a line-by-line port of the twisted program --
twisted's async (plus coroutines-light w/ via generators) seems like a
significantly different model than goroutines + channels. I wonder if they
actually implemented Deferred in Go?

~~~
jtolds
We implemented a future class that had very similar functionality to a
deferred. We used goroutines heavily but channels not so much.

I suspect we can improve go runtime scheduler performance by starting to go
through and replace pieces with channels where appropriate.

------
micro_cam
I really hope the go compilers will soon support shared object output so we
can write python extensions in go instead of having to fully dump one for the
other. I know it was a maybe for go 1.3 but I haven't heard much chatter and
fear it will get pushed backed.

~~~
jtolds
It's not going to be in 1.3 but the chatter is they might attempt something
for 1.4

~~~
micro_cam
I hope so, I have some analytical code I really want to wrap for R and Python
without the overhead other methods require.

------
stuaxo
Did you release your faster version of the Protocol Buffer library ?

~~~
jtolds
While we're planning on open sourcing some things, I'm not sure we'll ever
open source that one. Even though it was much faster, it didn't see much time
in production due to the less than desirable impact it made (go Amdahl's law),
and it still has some bugs and was highly customized to our specific protocol
buffer definitions.

Internally, Google has something faster for Python, but they haven't released
it yet. You might try putting pressure on them here:
[https://code.google.com/p/protobuf/issues/detail?id=434](https://code.google.com/p/protobuf/issues/detail?id=434)

[http://yz.mit.edu/wp/fast-native-c-protocol-buffers-from-
pyt...](http://yz.mit.edu/wp/fast-native-c-protocol-buffers-from-python/)
talks about the issues some more with some links to other rewrite attempts.

~~~
sandGorgon
would you have gone with thrift if you had to do it all over again ? I ask
because I saw the bug description and the glacial response ;)

~~~
jtolds
No, I think we're honestly even more sold on protocol buffers' wire format
than before.

That said, if I did want to go looking elsewhere, I think the main
serialization format I am really interested in is Cap'n Proto:
[http://kentonv.github.io/capnproto/](http://kentonv.github.io/capnproto/)

------
azatris
What are the disadvantages of using Go instead of Python?

~~~
NateDad
Testing can be more difficult in some cases, if you haven't carefully
structured your code. In python you can always monkey patch whatever outside
dependencies you have, whereas in Go, you can't do that without structuring
your code to allow it. Careful use of interfaces and dependency injection can
let you do it, but if you don't know to use that style, you can get big blocks
of code that become hard to test because they expect the whole operating
environment to exist, which may be hard to do during testing.

If you want to write code in a Domain Specific Language (even if that domain
is "math"), it's nearly impossible in Go. You can't do operator overloading or
all the really crazy hacking on the functionality of basic parts of the
language to make it work in fundamentally different ways (the way you can with
numpy etc). Go will always look like types, functions, and methods.

Right now, Go has no user-defined generics.. this is actually not a problem
for many projects, but if you happen to need a lot of specialized containers
for different types (like red black trees, graphs, etc), then it can be a
barrier. There are ways around it, probably the best way is just code
generation to duplicate the container code per type that you need. The other
option is just using interface{}, which is basically void* or "Object" for Go,
and casting in and out of it... but that can be slow.

There's probably some stuff I'm missing, but those are the major points that I
can think of.

~~~
jtolds
My guess is that if you've written code that's hard to test in Go, it's going
to be hard to write good, non-brittle tests in Python. It's not so much that
you need to write code amenable to dependency-injection to write good tests,
you just need to write modular code.

As a fan of DSLs, I actually do appreciate how easy it is to understand any Go
that anyone has written, since there aren't any cutesy DSL tricks anywhere.
So, yeah, it's hard/impossible to do DSLs, but that might not be a Bad Thing.

Generics is a (frequently discussed) downside. It's definitely a tradeoff. For
every container type we had, we had to make a copy of it or a typesafe wrapper
around it for every possible instantiation of the container with different
types. If you're used to coding by making flexible containers and so on,
that's definitely much more brittle and challenging in Go. Go peeps will tell
you that's part of a tradeoff they're willing to take.

------
bsder
Why not just bump your processing power?

No offense, but that was a hideous amount of effort for just 20% in one area.
An extra dollar or two spent on a hardware upgrade wins for everything.

------
azth
> provided that your problems are not algorithmic complexity

What does that even mean?

~~~
gjm11
It means "provided the reason your code is too slow isn't that its performance
scales very badly as a function of a parameter that, in practice, is not
small".

If your code takes time proportional to 2^2^n then for n=4 that's 2^16 x
constant, which is probably fine for any reasonable constant, and for n=6
that's 2^64 x constant, which is probably too much for any reasonable
constant, so if you're running into problems with n>=6 then moving to a
different language or faster hardware or more-micro-optimized code is not
going to help you.

On the other hand, if your code takes time of order n^2 and typical values of
n are in the thousands or millions, then the difference between C and Python,
or Core i7 and Z80, or sloppily written code and highly-bummed code with an
inner loop in hand-tuned assembler, may make a big difference.

~~~
azth
Thanks for the explanation. I am aware of that; however, the sentence I quoted
does not make sense grammatically; "algorithmic complexity" is not an
adjective.

~~~
gjm11
I did consider adding a final paragraph saying something like "I am assuming
here that you were sincerely asking a question rather than merely being rude
and snarky, but of course that may not be true", but decided to play it
straight.

So, having established that you were merely complaining about a grammatical
slip, and that despite asking "what does ... even mean?" you knew perfectly
well what it meant:

Yeah, I agree, it would have been more correct had they written something like
"provided that your problems are not a matter of algorithmic complexity" or
"provided that your problem is not algorithmic complexity". Congratulations,
you found a mistake. (Though not, I think, anything to do with thinking
"algorithmic complexity" an adjective.) But (1) so what? and (2) if I'm right
in detecting a subtext of "man, if they can make that mistake, why should I
take anything else they say seriously?", then I strongly disagree; anyone can
perpetrate the occasional grammatical error. (Just out of curiosity, I looked
at some of your recent comments, and found one having looked through
considerably less text than the length of the article in which you found an
error. I dare say one could do the same for mine. To err is human.)

~~~
azth
Points taken. In my favor; however, English is not my native language :)
Though I do definitely make lots of mistakes in my native one.

------
aet
Can someone explain why SpaceMonkey is better than Dropbox?

~~~
jtolds
Space Monkey is cheaper for more space - $49/yr for 1TB. Further, because
there's a device in your home, getting your data synced off your laptop is a
much faster process - you aren't bottlenecked by whatever Dropbox is
throttling your upstream at. Not to mention all of the DLNA, Samba, home media
system integration we're working on.

~~~
ternaryoperator
It would be good if you explained this more on your site. I couldn't figure
out what the device was for, nor whether it was required, etc. I'd suggest a
home page that clearly explains what you do and how it works. It's also not
clear what happens price-wise after the first year. Is there some fee to pay
for the device or just the $49/yr for the storage? Etc.

------
azth
Was the CPU pegged at 100% when using Python then?

~~~
jtolds
yep

------
jpatel3
fyi..login link fails on the site.

------
leccine
Well it is kind of obvious that a compiled language is going to be faster than
an interpreted one, especially the way how these interpreters work
([https://wiki.python.org/moin/GlobalInterpreterLock](https://wiki.python.org/moin/GlobalInterpreterLock)).
You can fool yourself with Twisted (or in Ruby with EventMachine, Goliath
etc.) but it gets so just a bit ahead. The surprising fact for me is that Go
is not as much faster. I was expecting a bigger gap in the performance between
Go and Python. Understanding where your bottlenecks are is crucial and it is
not super hard in Go. [https://www.datadoghq.com/2014/04/go-performance-
tales/](https://www.datadoghq.com/2014/04/go-performance-tales/) I guess the
SpaceMonkey guys might further improve the performance just by doing a
thorough analysis on their code.

~~~
Artemis2
Python has benefited from years of throughout optimization of the language for
real-world use. Go is still under heavy development and is not as optimized as
other languages that have devs focused on optimization (that explains why
node.js is a bit faster than Go for handling HTTP requests at the moment).

~~~
stock_toaster

      > (that explains why node.js is a bit faster than Go for handling HTTP requests at the moment)
    

Pretty sure node's http parsing is handled by http-parser[1], which is written
in C (originally pulled from nginx as I recall).

Go's http parser is written in Go.

[1]: [https://github.com/joyent/http-parser](https://github.com/joyent/http-
parser)

~~~
zimbatm
If I remember correctly the initial versions of node had the ragel-based http
parser from mongrel but then ryan rewrote it. http-parser is hand-written.

~~~
stock_toaster
maybe not entirely hand written? source[1]

[1]: [https://github.com/joyent/http-parser/blob/master/LICENSE-
MI...](https://github.com/joyent/http-parser/blob/master/LICENSE-MIT#L1)

------
sfk
And the website takes more than 30s to load...

~~~
bananas
At least it does load. A lot of sites fall over on a good HN'ing.

~~~
sfk
And a lot of sites survive just fine. I don't think "at least it loads" is
something to be proud of, especially when the topic is performance.

~~~
sigzero
Except their website isn't in Go. So it doesn't even pertain to the
conversation.

