Gobs on the wire

This week, I want to talk about how to use Go to write a client/server system with both synchronous requests and asynchronous event notifications. To help learn Go, I wrote a clone of the Conserver console server. Now, of course, the world didn’t need another console server, but it turned out to be an interesting experiment, because what a console server does is well suited to the tools Go gives a programmer. A console server’s job is to gather the output from one or more serial cables (or, when there’s a terminal server in the mix, one or more TCP connections implementing the Rtelnet “protocol”). It logs that output to files, and makes the output available in realtime to zero or more watchers. It allows one and only one of the watchers to be read-write, to actually control the device. ...

January 17, 2011 · 9 min · jra

The impatient producer

Last week I showed how a channel could link a producer and a consumer, and I idly speculated on how you’d set the depth of the queue, relative to the rate and variability of the producer and the consumer’s need for new input. This weekend, I got to thinking about my next interesting Go project. It will be an HTTP proxy that can do some nifty tricks to offload a slow Internet link. One of the features I thought I might add would be something to send all the new HTML it sees through a secondary processing system in order to find extra assets it might want to cache. This is a case of a producer that wants to act totally independently of the consumer. If the secondary processing goroutine is slow, or hung inserting something into a database, or whatever, the producer (the HTTP reply) can’t hang – he needs to reply to the client. ...

January 11, 2011 · 5 min · jra

Using a channel as a queue

I try to write a Go article every Monday, but the holiday season has disrupted me a bit. So here’s a little something I dug out of my stocking to get things going again. I thought an interesting way to play with the exp/draw package, the http client, and the image decoder would be a program to animate the tiles from Google Maps, showing the world scrolling by, as though you were in an airplane looking straight down and flying in a straight line. It came to me in one of those flying dreams… (not really). ...

January 3, 2011 · 6 min · jra

A simpler way to embed data

In my post about how to efficiently put data into a Go binary, I mentioned that strings are immutable, and can be accessed without causing the Go runtime to copy them. This turns out to be the key to a simpler way to achieve what I wanted to do. By simpler I mean, “no cgo”. That’s a nice simplification, because up until recently, your final static binary image linked to the cgo code dynamically, and that made using my technique impossible in the context of the Tiny runtime, where there is no dynamic linker. Recently cgo has changed, but at the same time, I’ve discovered how to use native strings to do what I want, so let’s see how it works. ...

December 17, 2010 · 3 min · jra

RTM's puzzle

Here is a little program to that implements RTM’s series for Cliff Stoll. package main import "fmt" func count(s []int) int { i := 1 x := s[0] for ; i < len(s); i++ { if s[i] != x { break } } return i } func next(s []int) []int { res := []int{} for len(s) > 0 { n := count(s) res = append(res, n, s[0]) if n == len(s) { break } s = s[n:] } return res } func max(s []int) (m int) { for _, x := range s { if x > m { m = x } } return } func main() { s := []int{1} for i := 0; i < 200; i++ { s = next(s) fmt.Println(len(s), max(s)) } }

December 17, 2010 · 1 min · jra

Where is bytes.NewReaderAt?

I have a nice source of []byte slices (see last post), and now I’d like to do something with them that resembles a filesystem. I was planning on just using a map from name to file contents, which would work ok. But then I remembered seeing the archive/zip package, and I thought how much cooler it would be to just make my prototype filesystem, zip it up, put the zip file into my Go program (see last post) and then access the filesystem via the archive/zip package later. ...

December 13, 2010 · 2 min · jra

Fat Constants, Thin Constants

I play from time to time with a patch for Go that makes the Tiny runtime more capable. My current goal is to get a new backend for exp/draw working which writes to the SVGA screen. It would be cool to be able to decode the Go mascot and have him flying around the screen or something. In the Tiny runtime, there’s no OS, so there’s no disk drivers, so there’s no filesystem, so there’s no files. Which makes decoding a PNG and showing it kind of hard. But if the program carries along the data with it, in the form of a []byte, then you could use bytes.NewReader to turn it into an io.Reader and then pass it to image/png.Decode. So that’s what I set out to do. ...

December 13, 2010 · 7 min · jra

Passing function pointers through channels in Go

Is is possible? Of course! package main func add(x, y int) int { return x + y } func mul(x, y int) int { return x * y } func runner(ch chan func(int, int)(int)) { for f := range ch { println("f(1, 2) = ", f(1, 2)) } } func main() { ch := make(chan func(int, int)(int)) go runner(ch) ch <- add ch <- mul ch <- add close(ch) } Is it useful? Probably, but this demo doesn’t show how yet… have to think about what patterns this makes possible. ...

December 3, 2010 · 1 min · jra

Where's all the magic? In the linker...

I have been trying to make a post per week about Go, but that requires learning something interesting during the week. I’m currently cycling between several little Go toys as I get the time. One is to make Go on raw hardware more useful/interesting. Another is a clone of the console server from conserver.com written in Go. Neither one of those little projects is at a point where I can really explain much about it, but not for want of trying… This week my Go console server project taught me that netchan cannot send channels (OK, I wasn’t really shocked at this, but I was hoping that it might work), and so I’ll need to make my own protocol, and include some proxy channel reader/writers at each end of the TCP connection to send the data into the channel like I want. On the raw-hardware side, I got stuck on code that ends up incorrect once it ends up in the ELF file. Go figure. ...

November 15, 2010 · 6 min · jra

Who said life is fair? The Go scheduler certainly didn't...

In my last post, I showed a program that had a strange behavior that caught my eye. I was trying to look at how Go handles shared access to globals, but the program also had the unintended effect of measuring the “fairness” of the Go scheduler. Here’s the program again, for context: package main import "runtime" var x int var ch = make(chan bool) func f(inc int) { for { println("f: ", inc) x += inc ch <- true } } func main() { go f(1) go f(-1) runtime.Gosched() for { _ = <- ch _ = <- ch println("main sees x = ", x) } } When you run this with GOMAXPROCS=3, and you are on a machine with at least three cores, you get precisely what you’d expect: three system threads, each one running one goroutine, and total fairness: f(1) happens once for every f(-1), and the long-run value of x is around 0, but sometimes higher or lower. ...

November 8, 2010 · 6 min · jra