Explain the use of Go's wait groups and semaphores for synchronizing and coordinating multiple goroutines in Go programs?