7 Go Bugs
Deadlock
func workerA() {
ALock.Lock()
defer ALock.Unlock()
for i := 0; i < 1000; i++ {
if(A[i] == 0) {
BLock.Lock()
A[i] = B[i]
BLock.Unlock()
}
}
...
}
func workerB() {
BLock.Lock()
defer BLock.Unlock()
for i := 0; i < 1000; i++ {
if(B[i] == 0) {
ALock.Lock()
B[i] = A[i]
ALock.Unlock()
}
}
...
}
WorkerA has key for A, tryna get B, but workerB has key for B, tryna get A. Nobody gets anything. Deadlock
Anonymous Function Scope
func do_processing(batch int) {
log.Println(“Working on Batch: ”, batch)
}
func main() {
batch := 0
for i := 0; i< 5; i+= 1 {
batch += 1
go func() {
do_processing(batch)
}()
}
}
Output:
Working on Batch: 5
Working on Batch: 5
Working on Batch: 5
Working on Batch: 5
Working on Batch: 5
Fix:
func do_processing(batch int) {
log.Println(“Working on Batch: ”, batch)
}
func main() {
batch := 0
for i := 0; i< 5; i+= 1 {
batch += 1
go func(batch int) {
do_processing(batch)
}(batch)
}
}
Slices
func add(slice []int, val int) {
slice = append(slice, val)
log.Println(slice)
}
func main() {
slice := []int{1,2,3,4}
log.Println(slice)
add(slice, 5)
log.Println(slice)
}
Output:
[1,2,3,4]
[1,2,3,4,5]
[1,2,3,4]
Because go is pass-by-value
Fix, pass the original array in
func add(slice *[]int, val int) {
slice = append(slice, val)
log.Println(slice)
}
func main() {
slice := []int{1,2,3,4}
log.Println(slice)
add(&slice, 5)
log.Println(slice)
}
Select and Timers
func main() {
…
for {
select {
case <-quit:
…
case <-ticker.C: //every 500ms
…
case <- msg_ready:
…
default:
log.Println(“Nothing to do!”)
}
}
Don't use time.After, use ticker.C