Google Go Lets Developers Work More With Multicore, Parallel Computing

 
 
By Jeff Cogswell  |  Posted 2012-11-05 Email Print this article Print
 
 
 
 
 
 
 


However, I should note that while this is different from runtimes such as Cilk Plus, the documentation for GOMAXPROCS does state, “This call will go away when the scheduler improves.” That tells me that Google has plans to make the scheduling more automatic so you don't have to manually specify the cores, making it more like Cilk Plus.

And indeed, by specifying cores, you can run into trouble. If you set GOMAXPROCS to the number of cores, such as eight, and then write a loop that schedules out, say, 60 goroutines to run in parallel, the scheduler starts exactly eight goroutines running, and subsequent calls to “go” to start a goroutine wait until a core becomes available. In other words, subsequent calls effectively become synchronous. Look at this code carefully:

runtime.GOMAXPROCS(8)

for i := 0; i<8; i++ {

    go func(c2 int) {

        fmt.Println("starting", c2)

        x := 0

        for j := 0; j<1000000000; j++ {

            x += 1

            x -= 1

        }

        fmt.Println(c2)

    }(i)

}

fmt.Println("Finished with for loop")

In this case, with eight virtual CPUs, the message “Finished with for loop” will appear immediately; the eight threads are spawned and the loop finishes, and the message prints while the threads continue to run. But change the loop to a nine, and it behaves differently. The ninth call to go pauses and waits for an available thread. Only when it becomes available does it run.

But wait. Things change if we modify the code a bit, and insert a call to Sleep inside the innermost loop.

Like most languages, Sleep yields the thread so other threads can run. And that gave me more clues to what's going on here. When I took the Sleep call back out, and instead changed my call to GOMAXPROCS(7), things work better. Why is that? Because the outer function needs a thread, as well. By allocating eight cores to our loops, the outer function can't continue to run asynchronously.

By lowering the number by one, things run much more smoothly and my outer function doesn't freeze up. Next, I made that change to the above code, and set the loop to 64. The scheduler launched 60 threads, and all calls to go remained asynchronous, letting the first seven run on the seven other cores; as each finished, the scheduler started the next thread waiting in line. The string “Finished with the loop” displayed almost immediately as expected, meaning my outer function continued to run.

The moral here? The scheduler could certainly stand for improvements, as Google seems to recognize. Be careful with it, and recognize the implications of playing around with GOMAXPROCS.

Functional Programming and Closures

Another topic I didn't touch on the last time around concerns closures. Closures are a powerful feature in dynamic languages such as JavaScript, but they can also be abused. In Google Go, if you have a function that spawns additional threads, and that function then ends before the threads do, its variables stick around until all the threads are finished. I tested this out and it worked fine.

The way I did it was by taking the code I just showed you and moving it out of the main and into its own function. I created a variable in that function, and let each loop-thread print out the value of that variable. It continued to work fine even after the function returned.

As for functional programming where functions are first-class objects, Go does indeed support that and always has. I also tested this out easily enough. But unlike a language like JavaScript, you have to declare user types for your functions, much like in languages such as C#. Rather than do a long write-up, I'll refer you to this blog on Google Gofrom a couple years ago that covers it nicely.

Final Analysis

I liked Go when I reviewed it the first time; I like it even better now. I'm seriously considering porting some of my Web-based apps to it and putting it on Google App Engine and seeing how they do. So far all indications are that they should perform very well. I'm going to make use of the multicore programming, but I'll be careful as I do, since it has some quirks. But the syntax and packages are modern enough that I shouldn't have to pull my hair out writing the code. Sounds like a win to me.



 
 
 
 
 
 
 
 
 
 
 
 
 

Submit a Comment

Loading Comments...

 
Manage your Newsletters: Login   Register My Newsletters























 
 
 
 
 
 
 
 
 
 
 
Rocket Fuel