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