Archive for Go

Priority-queued channel in Go

Right. So. I’ve been writing my standard hello-world Sudoku solver in Go. It reached a plateau about a week ago when some changes that I thought were going to make it faster actually made it slower. I think I did something to a function that stopped the compiler inlining it. Or something. The point is that I was getting diminishing returns from incremental improvements to the current code.

The next step is to add some concurrency. At the moment it does some steps in parallel in the puzzle-generation stage, but it’s still solving a single grid serially. (The general algorithm is: solve an empty grid; then visit each square, and clear it if the resulting puzzle still has a unique solution. Right now, the check for a unique solution (or rather, the search for other solutions, which is expected to fail) is happening in several goroutines.)

The approach I used with the Java version was to keep partial solutions in a priority queue, ordered by the number of squares filled (so that the next one out of the queue is the most complete). These were farmed out to a thread pool. The result was a more-or-less depth-first search of the solution space. For reference, the thread manager code is here. (IIRC, there’s a bug in it somewhere – it doesn’t terminate properly.)

Concurrency is one of the things that’s supposed to be nice in Go. The basic approach I’m going to take for the priority queue is to have two channels, tied together by a goroutine that reads items from the “in” channel, puts them into a heap, then pops from the heap and writes to the “out” channel.

This morning I knocked together the code to do this in abstract. (Well, with ints, anyway. I’ll try to abstract out the type before using it for the Sudoku stuff. Generics would be nice here – generics are one of the longest-standing items on the wishlist for Go – but I think I can see a Go-like way of doing it regardless…) There are some funny corner cases with blocking – it needs to read eagerly enough from the “in” channel that things don’t just pass through, but not so much that it starves the “out” channel – and I’m not sure I’ve got the most parsimonious version yet, but it seems to work. And compared to the Java version, it really is quite pretty. Okay, okay, it might be a bit messier by the time I add a couple of other things needed by the Sudoku solver.

So, yeah. Progress.

Leave a Comment