Things I like about programming in Go
blog.jgc.org
blog.jgc.org
And before anyone suggests "just use 64 bit", that actually a really crappy solution. In most cases it merely (almost) doubles your memory footprint for no real gain.
[1]: https://groups.google.com/group/golang-nuts/browse_thread/th...
http://codereview.appspot.com/6114046/
FWIW, the panelists on the recent "Go in production" panel at I/O responded that garbage collection wasn't an issue for them on 64-bit systems. http://www.youtube.com/watch?v=kKQLhGZVN4A
In Rust we have a very large patchset to LLVM to allow us to do this; it involves modifying nearly every stage of the LLVM pipeline. Curious how you did that in gccgo.
Edit: I just looked at the source and it still seems conservative for the stack and registers. So it's not a precise GC yet and will not eliminate false positives. (This is of course totally fine, I just wanted to clarify for myself.)
Also, if the problem is so pathological, it might be worth filling an issue.
Slightly off topic (but relevant to my comment above), do you know why this:
func TraverseInline() {
var ints := make([]int, N)
for i := range ints {
sum += i
}
}
should be slower than: func TraverseArray(ints []int) int {
sum := 0
for i := range ints {
sum += i
}
return sum
}
func TraverseWithFunc() {
var ints := make([]int, N)
sum := TraverseArray(ints)
}
Seeing a huge difference here. With an array of 300000000 ints, TraverseInline() takes about 750ms, whereas TraverseWithFunc() takes 394ms. With gccgo (GCC 4.7.1), the different is much slighter, but there's still a difference: 196ms compared to 172ms. (These are best-case figures, I'm doing lots of loops.) Go is compiled, not JIT, so I don't see why a function should offer better performance.2 theories on why gcc is doing better. Maybe its unrolling the loop, and avoids a bunch of jumps. Alternatively, it could be using SSE, but this theory is a much less likely, because I would expect it to be 4 times faster not twice as fast. gc doesn't use SSE instructions yet.
The Go authors should be very receptive and informative on such an issue.
For more complex functions, you could try profiling using the runtime/pprof package. More info here: http://blog.golang.org/2011/06/profiling-go-programs.html
If you want to dig deeper and are not averse to assembly, you can pass -gcflags -S to 'go build' and see the compiler output. Here's what I got for the above code:
--- prog list "TraverseInline" ---
0000 (/tmp/tmp.rkM3kSJ6Hd/trav.go:10) TEXT TraverseInline+0(SB),$40-8
0001 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVQ $type.[]int+0(SB),(SP)
0002 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVQ $300000000,8(SP)
0003 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVQ $300000000,16(SP)
0004 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) CALL ,runtime.makeslice+0(SB)
0005 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVQ 24(SP),BX
0006 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVL 32(SP),SI
0007 (/tmp/tmp.rkM3kSJ6Hd/trav.go:11) MOVL 36(SP),BX
0008 (/tmp/tmp.rkM3kSJ6Hd/trav.go:12) MOVL $0,DX
0009 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) MOVL $0,AX
0010 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) JMP ,12
0011 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) INCL ,AX
0012 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) CMPL AX,SI
0013 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) JGE ,16
0014 (/tmp/tmp.rkM3kSJ6Hd/trav.go:14) ADDL AX,DX
0015 (/tmp/tmp.rkM3kSJ6Hd/trav.go:13) JMP ,11
0016 (/tmp/tmp.rkM3kSJ6Hd/trav.go:16) MOVL DX,.noname+0(FP)
0017 (/tmp/tmp.rkM3kSJ6Hd/trav.go:16) RET ,
--- prog list "TraverseArray" ---
0018 (/tmp/tmp.rkM3kSJ6Hd/trav.go:19) TEXT TraverseArray+0(SB),$0-24
0019 (/tmp/tmp.rkM3kSJ6Hd/trav.go:20) MOVL $0,DX
0020 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) MOVL $0,AX
0021 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) MOVL ints+8(FP),SI
0022 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) JMP ,24
0023 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) INCL ,AX
0024 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) CMPL AX,SI
0025 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) JGE ,28
0026 (/tmp/tmp.rkM3kSJ6Hd/trav.go:22) ADDL AX,DX
0027 (/tmp/tmp.rkM3kSJ6Hd/trav.go:21) JMP ,23
0028 (/tmp/tmp.rkM3kSJ6Hd/trav.go:24) MOVL DX,.noname+16(FP)
0029 (/tmp/tmp.rkM3kSJ6Hd/trav.go:24) RET ,
--- prog list "TraverseWithFunc" ---
0030 (/tmp/tmp.rkM3kSJ6Hd/trav.go:27) TEXT TraverseWithFunc+0(SB),$40-8
0031 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVQ $type.[]int+0(SB),(SP)
0032 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVQ $300000000,8(SP)
0033 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVQ $300000000,16(SP)
0034 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) CALL ,runtime.makeslice+0(SB)
0035 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVQ 24(SP),DX
0036 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVL 32(SP),CX
0037 (/tmp/tmp.rkM3kSJ6Hd/trav.go:28) MOVL 36(SP),AX
0038 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) LEAQ (SP),BX
0039 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) MOVQ DX,(BX)
0040 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) MOVL CX,8(BX)
0041 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) MOVL AX,12(BX)
0042 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) CALL ,TraverseArray+0(SB)
0043 (/tmp/tmp.rkM3kSJ6Hd/trav.go:29) MOVL 16(SP),AX
0044 (/tmp/tmp.rkM3kSJ6Hd/trav.go:30) MOVL AX,.noname+0(FP)
0045 (/tmp/tmp.rkM3kSJ6Hd/trav.go:30) RET ,https://gist.github.com/3053930
The numbers are from Go 1.0 as that's what is available on Ubuntu Precise, my test box. (Getting similar numbers with 1.0.2 on a different box where I don't have gccgo.)
I realized that the first loop was using "i < len(ints)" as a loop test, which turns out to be more expensive than I thought, and the compiler doesn't optimize it into a constant (which would be expecting too much, I guess). After rewriting the test, the function call case is only slightly faster, although it is still significantly faster with gccgo.
for i := 0; i < len(ints); i++ {
sum += i
} sum += ints[i]for index, value := range mySlice { }
and you get the index and the value, or you can do
for _, value := range mySlice { }
If you only need the value.
https://github.com/elliottslaughter/llvm/tree/noteroots-ir
Currently, you are mostly out of luck if you try to use mainline, unless you're okay with the llvm.gcroot intrinsics, which pin things to the stack so they can never live in registers (causing a corresponding performance loss). Probably your best bet is to do what Go will do once the patch enneff was referring to is merged: scan conservatively on the stack and precisely on the heap. You can still get false positives and leaks, and you can't do moving GC that way, but it's better than fully conservative GC.
By far, the hardest part of GC is precisely marking the stack and registers. Yet you have to be able to do it if you want to prevent leaks. Our goal is to put in the hard work so that new languages will be able to have proper GC without having to roll a custom code generator or target the JVM or CLR.
As someone who has ambitions of writing a fun little language this is exactly what I want out of LLVM. Can't wait for your patches to hopefully get to mainline.
When will this be in the official release??
Also, Go works much better on 64bit systems for many other reasons, if nothing else because that is what most of the core team uses. 64bit certainly does not double your memory footprint, and it increases performance dramatically (in part because the extra registers, etc., and in part because the Go 64bit compilers are much better).
And as Andrew mentioned, there is a patch already to fully solve things for the few people stuck on 32bits that have any issues.
Finally, all this is an implementation detail, and has very little to do with the qualities of the language. which is what the article is really about.
I'm not sure what the proportion of people who experience issues is (whether it's "some", "most", or "very few"), but in my anecdotal experience running several long-lived Go processes on a 32-bit VPS it hasn't been a problem.
I think it just comes down to the allocation patterns in your program. Some programs trigger the pathological behavior and others don't.
Regardless of the numbers of affected programs, I'll be glad when the issue is behind us for good.
Not quite, but it does use a lot of extra memory:
http://journal.dedasys.com/2008/11/24/slicehost-vs-linode
I'm sure Ruby's memory usage characteristics are different than Go's, but still, it's worth paying attention to.
You do have a point about 32 bit, though (I use 32 bit Redis for instance, for the same reason).
Lots of issues with the runtime had to wait because they can wait because it doesn't matter if you wait 5 years to fix the GC because you won't break any code when you do it.
The page full of go libraries the OP points to is laughably small -- even Haskell does better.
The core language though seems quite nice. Although it looks to not support OpenMP, which is a shame.
EDIT: I understand that Go is young and thus can't match up directly with Python/Java/Perl/C in sheer number of libraries. I'm more concerned with the rate of change of language adoption and new library creation, which doesn't seem to be large. But, the enthusiasm in this thread is quite encouraging.
If I need to integrate features into a server that are more easily done in Python, I'll just launch a Python process from Go and communicate with it over pipes to get the functionality I need.
These are things that, obviously, aren't going to be on the top of a core dev team's priority list. They will come with time. But I can't do without them.
I don't know so much about bioinformatics, but I know some folks are using Go in that field without too much problem. Of course, the more specialized your needs, the greater the chances you might have to roll your own.
But given that Go 1 has hardly a few months old, this is not very surprising.
It is very early days (0.083 days to be exact) but I intend to support Hinton-style "deep learning" within the next few days.
I have a feeling that Go's concurrency features will make it a good fit for various ML workloads. And it's a rare combination of expressive and metal-close, which is good fit for prototyping crunchy algorithms.
The 'usual suspects' have library support for this (Ruby, PHP, etc etc): Go does not (so I invoke openssl from within Go instead).
Putting that aside, it is a great language and one I'm really enjoying using. I primarily work in Objective-C, so it makes a nice change!
Hell, Go even has an official ssh library, I don't think any of the 'sual suspects' has that ;)
Honestly the project is only a few days old and really sucks, but I found wrapping OpenSSL's SHA and AES features trivial. cgo is the most awesome FFI I've ever used. SHA hashing is actually faster using the OpenSSL version.
Please feel free to fork and add your features, in the meantime I'm working on adding support for a TLS listener/connection like crypto/tls.{listener,Conn}. http://golang.org/src/pkg/crypto/tls/
Go's libraries are, IMHO, very thin right now. Just of the things I've recently looked for, there's no TLS v1.2, no XML parsing of any sensible variety, and the SMTP library is a sad joke. But I'm still using Go daily.
And guess what? It's also fun to get to write the libraries.
On the positive side, the standard libraries are very consistent, the good 3rd party libraries tend to follow the conventions of the standard libraries (lots of decisions made in the language and tooling make it easier to do things the Go way than to treat it like it is another language) and if you really need some large chunk of functionality that Go doesn't provide and you don't have the time or willingness to make a pure Go version, you can easily pull C libraries in via cgo.
A few features that have really begun to draw me away from Python:
* A step away from object-oriented programming while still providing a way to associate functions with types via methods. I've been tending towards a more functional style in Python lately with functions and simple types instead of heavy OO code. * Static instead of dynamic typing. I find that I rarely actually benefit much from the dynamic typing features in Python and they can often be a source of bugs.
A couple of things I still find myself missing regularly:
* A full-featured unit testing library like Python's unittest * A simple interface for defining rich command-line argument parsers like Python's argparse
Is it that you didn't know about these libraries, or that they don't meet your requirements? If the latter, what do you require from each of them that they do not already deliver?
[1] http://golang.org/pkg/testing/ [2] http://golang.org/pkg/flag/
As for the flag package, it's fine for simple command-line flags but doesn't have anything to deal with specifying positional arguments. Sure you can get them from the Args() method but you have to basically write another layer of argument handling to deal with them. I like Python's argparse module's approach and flexibility there.
For value equality, just use reflect.DeepEqual[1]. The wiki also has a page on table driven tests, which is worth a read[2].
[1]: http://golang.org/pkg/reflect/#DeepEqual [2]: http://code.google.com/p/go-wiki/wiki/TableDrivenTests
Thanks for the pointer to the reflect package, I shall check it out.
Most people find that the libraries for both unit testng and arg parsing in the Go stdlib are more than enough (IMHO specially the arg parsing lib does way more than I would ever want in a command line program).
But some people have written more "rich" alternatives, see the Unit Testing and Command Line UI sections here:
http://go-lang.cat-v.org/pure-go-libs
Some of the libs there are outdated, but that is mostly because in practice almost everyone find using what the standard Go distribution provides works very well. (If there is some functionality you are really missing you could fill an issue, but you would have to make a convincing case as to why it is needed.)
Anyway, neither of those cases are by any means a major downer, just two things that have been niggling me from time to time.
haven't taken time to turn it into a proper library.
However, I wish that python have some of the cool things of GO (like gorutines) and other stuff like in cobra-language.com and:
1- Removal of null (using maybe as haskell) 2- Decimal instead of float as default
Still, the new languages refuse to fix #1. #1 Must be declared a goal like have garbage collection right now.
After all, in Python, there is no actual Null-pointer exceptions; instead, you have TypeErrors that just happen to trigger on None. Even if you had some sort of option type, you would still get runtime errors because there is not enough information to deal with them at compile time.
Now, you could add some sort of abstractions to make checking for None in your code easier. But when your "benevolent" dictator hates folds, you're not getting any advanced features like monads any time soon!
The type system in Haskell look very good. But the cobra language have a implementation very close and in line with the spirit of python...
Wha...? Have you spent any time with it at all?
I'm particularly wondering about code other than Web apps with hundreds of simultaneous users, such as single-user statistical AI/machine learning or other performance-demanding apps where Python has to delegate to libraries written in C.
This would be at first to provide "backend" services to currently running applications, so the latency overhead is important.
To be honest my personal viewpoint is that we're better off reducing our dependence on SIMD CPU instructions and using GPUs for this sort of highly-parallel processing instead. Most Processors sold these days come with a GPU built-in, so why not make use of these SIMD units, rather than duplicating them on the CPU? This is just my opinion though, and is sort of irrelevant to the question.
Go has an excellent interface to C (cgo) built in, and SWIG can also be used to wrap C/C++ libraries so they are usable in Go. If your aim is core-for-core speed, then your best option is probably to take some highly optimised C/C++ library and create a wrapper that allows you to access it from Go. This route would be at least as performant as any python implementation using the same technique, if not much faster. If your goal is having a highly-concurrent and safe implementation, it is better to implement such libraries from scratch in Go; this is the method most Go libraries use.
Just as with benchmarks, I don't think anyone can give you a non-subjective answer on whether Go will be faster (so take mine with a grain of salt).
[1] http://shootout.alioth.debian.org/u64q/benchmark.php?test=al...
For the calculations that don't work well on the GPU due to small data sets, simple calculations, or bandwidth constraints we could just run the code in parallel across multiple cores/multiple goroutines.
I think eventually (and this seems to be the direction companies like AMD are headed in) we'll have a couple (maybe up to 4) big cores right next to a bunch of smaller whimpy GPU-like cores which handle SIMD, making SIMD on big cores all but redundant. We're not there yet but AMD and Intel are both working on trying to get their on-chip GPUs to share memory with the processor directly. At the moment the focus for this is mainly gaming performance, so textures, etc. don't have to be copied from main memory to the GPU; the same functionality will greatly benefit GPGPU though. Once we have this heterogeneous architecture and newer faster memory technologies, the problems with using the GPU for SIMD will disappear.
But for the moment, with the real-world technology constraints we have, you're absolutely right on the limitations of GPGPU.
You do realize that Go compiles to machine code and Python is a dynamically interpreted language?
The obvious answer is that the Go standard library packages (http://golang.org/pkg/) are written in Go, including crypto code (e.g., http://golang.org/src/pkg/crypto/sha1/sha1block.go), but many of the Python standard libraries are written in C for performance reasons.
For file I/O and network bound applications (e.g., Django) Python is a great choice, but if your app involves any serious computation Go is much, much faster than Python (or Ruby, Perl, PHP etc.).
Python does have excellent 3rd libraries for computation like Numpy but the actual number crunching code is written in C or Fortran.
Which doesn't matter much if Go's machine code/runtime is inefficient or if Python libs are written in C in the first place whereas Go's are written in Go.
http://shootout.alioth.debian.org/u64/program.php?test=pidig...
http://shootout.alioth.debian.org/u64/program.php?test=pidig...
The underlying OS threads will do that, but if goroutines aren't 1-1 with OS threads (which I don't believe they are), how is this achieved? Are all current syscalls intercepted?
What about calls out to external C libs which in turn call blocking syscalls?
(I could test, but if go happens to be running all my goroutines in their own OS threads, I could get a false positive "pass")
Calls to external C libs are treated the same as syscalls.
A fast read suggests both syscalls and call to C code (cgocall) are used to switch goroutines.
Thats just off the top of my head how I'd handle it. I imagine with some more thought you can come up with a better mechanism.
The magic trick is that it runs the scheduler just before the blocking call, and if need be it will spawn a new thread to make the blocking call in. That way the thread that thinks it made the blocking call is free to continue running other goroutines.
Two questions to people that use Go:
1. Does Go have a good debugger that is easy to use? i.e. I shouldn't have to mess with the command line, but preferably use it directly from something like eclipse. It should work even in Windows.
2. Is goclipse working properly? Last time I used id, while it would show the syntax fine, the build and run was not working. I had to use the command line.
I think a language should be developed together with its tools. Right now Go is lacking in this department.
If you attempt to use the 32 bit gdb, you'll get errors about the executable you're attempting to debug is in an invalid format
Not as easy to use as a lot of debuggers, but it's widely known.
I don't know about Goclipse; I do all my development on the command line.
A lot of people will probably not like this answer, but Go's "tools" are the Acme editor and the shell. If you're running on Windows, Acme-SAC (https://code.google.com/p/acme-sac/, or just running Acme under "vanilla" Inferno) is a viable option, and is written in Limbo, a precursor to Go. (It still has some features Go lacks, but is roughly comparable.)
I wouldn't hold my breath on getting former Bell Labs guys to work on a graphical debugger or Eclipse support, so the language is somewhat unlikely to be developed together with those tools.
I wouldn't expect them to, and I also really can't understand the appeal of something as complex as an IDE to write code in a language as simple as Go, but Goclipse has been around for a while, and there is support for other IDEs:
http://code.google.com/p/goclipse/ http://go-lang.cat-v.org/text-editors/
I also suggest you to try gdb from the command line.
Debugger: http://golang.org/doc/gdb
The latest Zeus beta includes support for the Go Build, Clean and Run commands via the Zeus workspace.
Here is a video that shows how it works: http://youtu.be/9MeyFdRe6xM
NOTE: Zeus is shareware, runs natively on the Windows and can run on Linux using Wine.
Jussi Jumppanen
Author: Zeus Editor
As a compiled language, Go gets usually compared to the experiences people have with C and C++.
The reality is that 90% of Go features are available in the Pascal family branch of programming languages since the early 80's.
So most features that people enjoy in Go are all features that would already be mainstream, if the Pascal branch had won over C to become mainstream.
Even the ability to use a language like Go for systems programming has been proven in the Native Oberon OS and its descendents (A2) at ETHZ.
I had taken a look at Oberon back in 1999 and found it so much worse than Delphi for writing real programs. (which was a precursor of C#/Windows Forms, not Go).
CSP and static duck typing belong to the missing 10% I noted.
Still there are available in other languages that also support native code generation with modules.
> I had taken a look at Oberon back in 1999 and found it so much worse than Delphi for writing real programs. (which was a precursor of C#/Windows Forms, not Go).
Go method definitions are taken from Component Pascal, an extension to Oberon.
Actually I find Delphi much more powerful than Go for large scale development in the enterprise world.
Do you want to have the ticket numbers and Mercurial branches information?
I don't share your opinion on Go syntax, although, I like Pascal family much more than C and had been using Pascal/Delphi almost exclusively for all my projects until 2003. After that, Delphi became too outdated and I had to switch to other languages.
Also, as I have said before, my knowledge about Oberon and Component Pascal is theoretical, so it might be that you're actually right. Given that these languages are effectively dead (by github criteria: it does not recognize Oberon or Component Pascal, but supports DCPU16 assembly), I don't have a chance to improve this situation (any program written on dead language is theoretical, because it would not be used in prod)
I did contribute the initial version of the os.user package for Windows, which was then picked up by the core team. Also started to add Windows to the exp.gui/draw packages, but gave up on them when they were dropped from Go 1.
I find github criteria a bad one, as many people I know don't even care about it.
Oberon is still pretty much alive for ETHZ students as Active Oberon, just check the list of possible assignments, http://www.nativesystems.inf.ethz.ch/WebHomeProjects.
You can see the original method syntax for Component Pascal here, http://www.oberon.ch/pdf/CP-Lang.pdf, section 10.2.
I still lurk in the Go mailing list as a language geek, but lost interest, as the language feels too minimalist to my taste, given my experience with other languages.
In a way I belong to the group Rob recently described as C++ programmers. Given my experience in language design, using Go makes me feel I am back in high school with Turbo Pascal 6.0.
But Google's weight might nevertheless help Go become mainstream, who knows.
The batteries-included toolchain including gofmt and the go command are another pleasure while developing.
As far as languages I've dabbled with in the last few years Go was definitely the easiest to get started with in terms of the development toolchain.
Having no prior experience with Go, I found the rest of the article informative!
Writing your code in blocking style is just easier to follow than the callbacks used in Node and other asynchronous event servers.
[1]: well nearly the same. Somewhere in the binary, a call to set maxprocs is present. Same exact program differing only in the param to this call (i.e. 1 vs 2).
The reason that interest me is that I like Generics aka parametric polymorphism but I feel like Scala, Haskell and OCaml take it almost to the extreme particularly since those languages also have type inference. So it can be overwhelming for a new user.
That being said if Rust was more mature I would prefer it over Golang (here is another hacker news comment on this: http://news.ycombinator.com/item?id=1951467).
This person doesn't seem to have much experience with error handling.
You shouldn't deal with errors the way you prefer it, you should deal with them the right way. Sometimes, it's where they occur, but very often, it's somewhere up the stack.
We learned this lesson in the 90's.
Try writing a few things in Go. I very much doubt you'll respond like this afterwards.
One new way I've found interesting in obj c is giving functions (an) error handling block argument(s). It nicely does what java unhandled exceptions warnings do: make the user aware of his actions.
Accusing the author of this article of being "inexperienced" is also very amusing: http://en.wikipedia.org/wiki/John_Graham-Cumming
And even Java and C++ luminaries like Bruce Eckel have come out in support of Go's error handling and against exceptions.
"I'm sure some people reading this are going to say "But language FrobBub has had NoduleFoos for years cretin!"."
Priceless :-).
Here is a good detailed analysis why exceptions might be a worse choice: http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/35294...