Quantcast
Channel: Hacker News 100
Viewing all articles
Browse latest Browse all 5394

Go as an alternative to Node.js for Very Fast Servers——Study Golang,Go语言学习园地 官方论坛 - Powered by Discuz!

$
0
0

Comments:"Go as an alternative to Node.js for Very Fast Servers——Study Golang,Go语言学习园地 官方论坛 - Powered by Discuz!"

URL:http://bbs.studygolang.com/thread-278-1-1.html


Node.js has gained acceptance in mainstream software development at an amazing pace. There are a lot of good reasons for this: everyone loves software that is Very Fast, npm is truly an excellent package management tool/ecosystem, and its release coincided with the web development community as a whole awakening to the fact that JavaScript is a Real Programming Language. However, I think there are assumptions lurking in the subtext of the conversation around Node that are false, yet have contributed greatly to the excitement around it. I’ll whine about this briefly below:

  • Just because JavaScript is a real programming language doesn’t mean it is awesome. Crockford infamously has said that JavaScript is the only programming language that programmers don’t think they have to learn in order to use. I think that statement is less true today than even two years ago; both exposure to more serious JavaScript development and to a wider range of programming languages have taught us that we can view many JavaScript “bugs” — like function scoping, prototypal inheritance, and mutable execution context — as “features” that we can leverage to build better software. However, it is still a language where the commutative property does not always apply, where variables default to globals unless specified as locals, and where integer values do not exist. The focus in JS language development now is “more features with backwards compatibility in the browser.” Before I run this language on my servers, I want some fundamental design decisions overturned.
  • Conventional wisdom (and indeed the rationale called out by Ryan in his early slides on Node) says that putting JavaScript on the server means opening doors for front-end engineers to start churning out back-end code. Look ma, callbacks! I find this objectionable. If your JavaScript developer is capable of understanding JavaScript as a language, and has learned the DOM API, plus maybe some fancy HTML5 storage APIs, she is absolutely capable of learning a modern server-side framework in a different language. There may be emotional or psychological barriers to doing so, but not intellectual, and besides, learning new languages tends to broaden your understanding of the ones you already know.
  • Of course, it may be that you look down on your front-end folks and don’t consider their work “real engineering”. If you are in fact right, why on earth are you willing to give them a database connection? This thinking places too much burden on the tools and not enough on the user.
  • The biggest promise that Node makes is the ability to handle many many concurrent requests. How it does so relies entirely on a community contract: every action must be non-blocking. All code must use callbacks for any I/O handling, and one stinker can make the whole thing fall apart. Try as I might, I just can’t view a best practice as a feature.

Erlang, Scala, and Clojure are a few other platforms that have been touted in recent years for their scalability, but my favorite of this new pack is Go. Go was developed at Google by a couple of UNIX legends to replace C++ as a language for writing servers. As such, it delivers comparable speed to Node on a single-core machine and a much lower memory footprint (when configured correctly, Go will take advantage of multiple cores). This is not, however, what appeals to me about Go. While JavaScript drags the scars of its hasty standardization around with it, Go was designed very thoughtfully from the beginning, and as a result I find that it’s a pleasure to write. Though I’ve used Node and write a lot of JavaScript, I have gone to Go for servers for personal projects for the past year. Here are a few of the reasons I like it so much.

Static types with less, uh, typing

Go is statically typed. I personally love static typing, all performance considerations aside — it reduces the number of runtime errors I encounter and then number of unit tests I have to write, and is self-documenting by nature. The Go team mercifully designed a compiler that is quite smart about inferring types, which results in far less ceremony than you might expect.


Another aspect of the Go type system that I love is Go’s notion of interfaces. Interfaces are implemented implicitly. There is no “implements” keyword. Any type that defines the methods listed in a given interface type implements that interface by definition. This means that you can define interfaces that are implemented by code in the standard library, or in some other third party code that you don’t want to fork. The result is duck-typing that is compiler-enforced rather than simply a convention.

Shipping with the right tools

The Go team has gone out of their way to ensure that installing the language itself is all you need to start being productive with the language. Sometimes this means providing tools that you would expect the language community to produce after a few years. Sometimes it’s a question of making a decision on a contentious issue, so you don’t have to. And sometimes it’s just a great idea.


I particularly like Go packaging. The go get command fetches packages from any website that complies with a simple meta tag protocol, plus major source control hosting sites. All I need to do to make it possible for you to install my code is put a valid go package (a folder full of .go files that have the same package declaration) up on Github.


The Go source comes with syntax highlighting and other niceties for a number of editors, including an emacs mode and vim plugins. The vim plugins provide access to the built-in documentation generator (go doc) and the automatic coding style compliance tool (go fmt). go fmt parses your source and rewrites it using the AST and official formatting rules. There’s no arguing about whether to use semicolons, or putting your commas at the front of the line — the language knows what it wants. It’s a built-in hipster suppression mechanism.


An upshot of having command line tools that manipulate an AST is go fix, which will rewrite your source to accommodate API changes in the standard library or builtins if you upgrade your language version. I’ve only done this one, but it worked. I cannot get over how cool this is.


First-class concurrency

Go has first-class function values, so you could, in theory, prevent blocking I/O with callbacks (thought admittedly there would be a lot more cruft). But Go does much better than this: it provides keywords, operators, and primitive types that deal specifically with concurrency. This breaks down into:

  • The go keyword, which invokes a function as a goroutine— that is, a concurrently executing bit of code that you aren’t waiting on;
  • Goroutines communicate via channels, which are typed queue structures that are safe to share. These are basically like Unix pipes;
  • The <- operator, which as an infix appends a value to a channel, and as a prefix retrieves a value from a channel.


Robust standard library

Despite being a young language, Go has a very complete standard library. It addresses many of the needs of people who are writing systems software (there are 17 subpackages of the crypto package) but also more modern concerns like HTML templating with proper sanitization, JSON, and a really great HTTP package. There are also some officially maintained repositories outside of the stdlib that deal with newer protocols like websockets and SPDY.


This post could use more than one obligatory example, but if it has to be one, it should cover all my points above. We are going to port the first Node.js program I ever saw (from the slidedeck Ryan was using three years ago) to Go. It’s a small server that sends down 1MB responses for every request, perfect for testing handling of concurrent connections. The original looks like this:

Cpp代码,请使用工具条复制代码

http = require('http')
Buffer = require('buffer').Buffer;
n = 1024*1024;
b = new Buffer(n);
for (var i = 0; i < n; i++) b[i] = 100;[/i]
http.createServer(function (req, res) {
  res.writeHead(200);
  res.end(b);
}).listen(8000);

We can write this program in Go with a similar line count and equal simplicity and clarity. It looks like this:

Cpp代码,请使用工具条复制代码

package main
import "net/http"
func main() {
    bytes := make([]byte, 1024*1024)
    for i := 0; i < len(bytes); i++ {
        bytes = 100
    }
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write(bytes)
    })
    http.ListenAndServe(":8000", nil)
}

In this small space, we see type inference and use of the standard library. What you don’t see (by design) is that every call to the handler function passed tohttp.HandleFunc is invoked as a goroutine, thus handling any concurrency needs for us.


If you are using Node.js on the server and speed is a major factor in that decision, I encourage you to install Go and dump the code above into some files. You can run the Go server with go run yourfile.go. Run ab -c 100 -n 10000 http://{your ip}:8000/ in another terminal window, and use the tool of your choice to monitor memory usage. It’s pretty fast!

Now, if you’re not chicken, do the same with the JavaScript.


原文地址:http://techblog.safaribooksonlin ... -very-fast-servers/

Viewing all articles
Browse latest Browse all 5394

Trending Articles