First, go:
$ ab -c 100 -n 10000 http://localhost:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 1048576 bytes
Concurrency Level: 100
Time taken for tests: 10.085 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 10489017384 bytes
HTML transferred: 10487857152 bytes
Requests per second: 991.62 [#/sec] (mean)
Time per request: 100.846 [ms] (mean)
Time per request: 1.008 [ms] (mean, across all concurrent requests)
Transfer rate: 1015729.90 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 2 0.8 2 6
Processing: 21 99 5.6 98 137
Waiting: 1 3 2.7 2 41
Total: 25 101 5.6 101 139
Percentage of the requests served within a certain time (ms)
50% 101
66% 102
75% 103
80% 103
90% 105
95% 106
98% 108
99% 112
100% 139 (longest request)
Secondly, node.js: $ ab -c 100 -n 10000 http://localhost:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 1048576 bytes
Concurrency Level: 100
Time taken for tests: 15.765 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 10487558651 bytes
HTML transferred: 10486808576 bytes
Requests per second: 634.31 [#/sec] (mean)
Time per request: 157.653 [ms] (mean)
Time per request: 1.577 [ms] (mean, across all concurrent requests)
Transfer rate: 649639.92 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.7 1 11
Processing: 2 156 34.7 159 272
Waiting: 1 47 29.7 42 136
Total: 2 157 34.7 161 273
Percentage of the requests served within a certain time (ms)
50% 161
66% 174
75% 182
80% 187
90% 198
95% 209
98% 221
99% 227
100% 273 (longest request)
Not only does go serve the traffic more quickly, but it also has a much lower standard deviation between slow and long requests. Impressive. Percentage of the requests served within a certain time (ms)
50% 161
66% 174
75% 182http://eric.themoritzfamily.com/websocket-demo-results-v2.ht...
Has Node.js, Erlang, Scala, go and a lot of Python. On EC2 Erlang and Java pretty much blow everything else out of the water.
Go: No one knows this language, there's a small-but-growing community, there are enough libraries to get a lot done, and you get even better performance
Java: They are paying me (money!) to write in this language
For comparison: http://www.reddit.com/r/javascript (27,041)
Go would be one of the first things I'd reach for if there's any chance server-side concurrency would be involved. The language is minimalistic and unsurprising to the extreme. A joy to program in and use.
Go: The language is in its infancy, growing at a slow pace for now, bears some promises that are yet to be confirmed.
Java: For some reason people still hate the language even though it's the closest to being the most versatile language around (in every single aspect that makes a good language it ranks well against the others)
In every respect that a PHB may care about, perhaps. I think you should examine that "for some reason" more carefully before declaring that all reasons favor Java. Clearly there is something going on there, unless you think everyone who dislikes Java just suffered head trauma or something.
http://www.paulgraham.com/pypar.html
It sure seems Scala's in this "python paradox" land now. My guess is that you need some startups make it big using Go to evangelize it. Google using it is interesting, but I'm not sure it makes it "cool".
Though, I'm not sure Java was ever a language you could use as a skillset filter. Hm.
I don't follow the mailing list anymore, so I don't know if it already led to the same "cargo cult" fanboyship that Plan 9 sometimes evokes, where a lot of the idiosyncratic opinions of its developers (e.g. "shared libraries are bad") are basically never questioned and repeated almost like holy scripture.
Depends a lot on your interpretation of "Cool" though.
This is very true. Go is a pleasure to write. In fact, it's such a pleasure then when you hit something that wasn't really well designed it's horrid.
I wish Go stays on that path for a long time. And it never gets TOO big, which makes for awful communities.
In particular, OCaml has an awesome module system and a great take on structural sub-typing combined with proper type inference and sane parametric polymorphism.
Having actual algebraic data types is night and day to Go's more limited structs. OCaml also has a good object system which people don't use too often but can come on very handy.
Also playing with Racket, Clojure, and good ol' Common Lisp.
{-# LANGUAGE OverloadedStrings #-}
import Snap
import qualified Data.ByteString as BS
main :: IO ()
main = httpServe (setPort 8000 emptyConfig) $ writeBS $ BS.replicate (1024*1024) 100
I'm benchmarking it currently, but my laptop's network stack seems to break ab. It's also probably faster to build the response incrementally using an Enumerator, but I've never used Snap's Enumerator library and this is slightly closer to the design being tested in the other servers since it'll allocate the whole bytestring instead of writing it lazily.Go code will look a little less DRY to you as a result, which is a fair criticism, but it makes up for that by being incredibly opinionated (that's a good thing), being incredibly easy to prototype in, and being incredibly easy to refactor painlessly.
Go was such a huge relief after that horrible catastrophe language that seems to still continue to wreck new generations. Please, please, don't poison your career on focusing on a single language, especially one as disturbing as Haskell.
I found the (good) result that I could spawn a new goroutine for each incoming connection with minimal (~4k) overhead. This is pretty much what you'd expect since a goro just needs a page for it's stack if it's doing no real work. I had something like 4 VMs each making ~30k conns (from one process) to the central go server with something like 120k conns.
I found one worrying oddity however. Resource usage would spike up on the server when I shut down my client connections (e.g. ctrl-C of a client proc with ~30k conns).
Reasoning about things a bit, I think this is due to the go runtime allocating an OS thread for each goro as it goes through the socket close() blocking call. I think it has to do this to maintain concurrency. So I end up with hundreds of OS threads (each only lives long enough to close(), but I'm doing a lot at the same time).
Can anyone comment:
- is this guess as to the problem likely to be correct?
- is this "thundering herd" a problem in practice?
- are there ways to avoid this? (Other than not using a goro-per-connection, which I think it the only idiomatic way to do it?)
My situation was artificial, but I could well imagine a case that losing, say a reverse proxy, could cause a large number of connections to suddenly want to close() and it would be a shame if that overwhelmed the server.
https://code.google.com/p/go/issues/detail?id=4056
An interesting point raised there is that if they instead used a limited thread pool for all goroutines to share when making OS calls you could produce deadlocks.
I highly doubt that it is creating a thread per goro on client disconnect. If you have a minimalish example of this, the golang mailing list would be very interested in working with you to identify what went wrong and create a patch if it is an issue with the Go implementation.
Close isn't a blocking call, though.
The biggest thing Go gives me is that it's really easy to manage code bases that grow organically - refactoring a project that grows from 50 LOC to 5000 LOC is almost painless in Go - no other language that I've seen has dealt with this aspect of code development so well.
Very interesting to hear. Any chance you could expand on this a bit more?
Second, "start coding in XXX without learning a new language" is a terrible selling point. I've seen this thinking appeal to misguided PHB-types and witnessed the result: immense organizational damage. In my experience, this isn't a necessary or sufficient selling point to good developers. Learning a new language just isn't that hard, and a big part of a shift like this is actually in learning the new environment's paradigms, APIs, and best practices.
To make the latter point more strongly: if you're having doubts about your ability to pick up a new language, definitely take some time to learn a few new languages. Do a tutorial, play with a few small projects, enough to get the flavor of the language. Your hackery will benefit immensely from this, even when you return to your primary language.
Personally I hope that Go does just as well, if not a lot better. I am a bit of a fan of both.
https://gist.github.com/jamwt/5017172
Haskell was ghc 7.6.1 with ghc --make -O2
Go is go1.0.2 with "go build".
Both the go and nodejs versions completed without problems.
I was a little disappointed -- I was actually hoping I'd see comparable performance -- even if it is a silly test.
I think it is interesting that simple, idomatic code in go and nodejs didn't crash -- not sure what assumptions might be "wrong" in the underlying haskell code (I'm guessing if anything should be "fixed" it is in the web server libraries used).
But what I don't like: the negativity against Node and omitting some facts. In the replies of the orignal post a guy tested two (!) times Node and once it was significantly faster (v0.6) and once it had same speed (v8.0). So, why has mjijackson such different results in this thread at the top?? And maybe we should test it on real servers and not on a MBA. Moreover, we have here some micro benchmark which possibly doesn't reflect reality well. Don't get me wrong, I appreciate any benchmarking between languages but then please do it right and make no propaganda out of it. Further, Go's package manager seems to be nice but it does NOT have version control. How do you want to use this in a serious production environment. Maybe version control will come (but then tell how without loosing its flexibility) or not but this is something serious and definitely not an alternative to any server environment except for some mini services.
EDIT: downvoting is silly, propaganda and won't help the Go community in getting more credibility, better do some further benchmarks; otherwise this post/thread is full of distinct misinformation and should be closed
If you want to lock down the versions of all the software you're deploying in your organization, that's easy to do too. Just "git clone" all of the libraries you use to some internal server (and/or github repos), and change the URLs to point to that server. You control when everything gets updated.
Golang builds static binaries anyway. So if you test a binary and it works, you just copy it to all the servers you care about and you're done. If you're in a small and informal shop, maybe you don't need to mirror every repository. Due to the nature of git, if the upstream repo ever gets deleted, you can fall back on a local copy of it anyway.
This is all very much in contrast to languages like Java where keeping around the proper version of every jar and carefully deploying that version (and only that version!) on each server is big deal (and despite OSGI, still very much an unsolved problem.)
This is a small flaw in the go packaging system (and it is a flaw) which I'm sure they'll fix, either with a convention to always use branches for versions (which I guess is doable, but only if it becomes widespread), or by changing import to take an argument for the version. So something like:
import "github.com/gorilla/mux/1.0.3"
or import "github.com/gorilla/mux", ~> "1.0.3"
which would let you specify any minor updates say and possibly other permutations, and thus might be more flexible. I believe a few things have been suggested on the list but I haven't followed the conversation, not sure what the outcome was - perhaps just that it needs further thought.At present the first solution is possible, BUT it needs to become a convention which everyone follows in order to be useful (involving named branches or tags at the repo). The other advantage of this is that it states requirements fully in the package concerned - otherwise all we know is that this code requires github.com/gorilla/mux, not which version or when it was last tested/imported, whether it will work with the latest release or not, etc. But then it would let you run into conflicts by accidentally importing two versions of the same package with different paths.
The current convention of no version certainly puts more onus on the package maintainers to maintain backwards compatibility, or on users to maintain their own library of packages which they periodically update, and I see the arguments for it.
Of course none of this matters if you're just one person using packages to build an app at one moment in time, but if you yourself supply packages/apps to others, or want to setup members of an org over time with the same set of packages in the same state, and rely on other packages to compile yours, it can become more complex.
Other package managers tend to have a central point to adjust package dependencies, and make sure packages are always available forever at the same uri, so it'll be interesting to see how go manages this when go packages become more complex and widely used, start to be removed by maintainers, and start to have complex chains of dependencies on specific versions, or whether the much simpler go system in the end leads to a saner situation and puts the onus for this problem back on end users.
You can do that with lots of languages, using one of the langX->javascript compilers.
>Avoiding discrepancies in the same form validation written in two different languages
What form validation are you doing in javascript? I can't actually think of any client side validation that isn't just a regex.
Nonblocking I/O isn't just a "best practice" in the sense that consistent indentation is a "best practice," it's a core tenet of the Node ecosystem. Sure, you could write a Haskell library by putting everything in mutable-state monad blocks, and porting over your procedural code line-for-line. It's allowed by the language, just like blocking is allowed by Node. But the whole point of Haskell is to optimize the function-composition use case.
The Node community has the benefit of designing all its libraries from scratch with this tenet in mind, so in practice you never/rarely need to look for "stinkers" unless they're documented to be blocking. And unless they're using badly-written blocking native code, you can just grep for `Sync` to see any blocking calls.
Major point for saving man hours right there.
Does anybody from HNers use Go with websockets? What package do you use?