Goroutines
One channel
One-to-one dead lock
func main() {
chA := make(chan int)
go func() { chA <- 0 }()
for a := range chA {
fmt.Println("A:", a)
time.Sleep(time.Second * 1)
chA <- a + 1
}
}
One-to-one
func main() {
chA := make(chan int)
go func() { chA <- 0 }()
for a := range chA { // consume one
fmt.Println("A:", a)
time.Sleep(time.Second * 1)
go func(a int) {
chA <- a + 1 // produce one
}(a)
}
}
One-to-many dead lock
func main() {
chA := make(chan int)
go func() { ChA <- 0 }()
for a := range chA {
fmt.Println("A:", a)
for i := 0; i < 10; i++ {
chA <- i
}
}
}
One-to-many
func main() {
chA := make(chan int)
go func() { ChA <- 0 }()
for a := range chA { // consume one
fmt.Println("A:", a)
for i := 0; i < 10; i++ { // produce many
go func(i int) {
chA <- i // no sequence guaranteed
}(i)
}
}
}
Two channels
One-to-one
func main() {
chA := make(chan int)
chB := make(chan int)
go func() { chB <- 0 }()
go func() {
for a := range chA { // consume one
time.Sleep(time.Second * 1)
fmt.Println("A:", a)
chB <- a + 1 // produce one
}
}()
for b := range chB { // consume one
fmt.Println("B:", b)
chA <- b + 1 // produce one
}
}
One-to-many dead lock
func main() {
chA := make(chan int)
chB := make(chan int)
go func() { chB <- 0 }()
go func() {
for a := range chA {
time.Sleep(time.Second * 1)
fmt.Println("A:", a)
chB <- a
}
}()
for b := range chB {
fmt.Println("B:", b)
for i := 0; i < 10; i++ {
chA <- i
}
}
}
One-to-many
func main() {
chA := make(chan int)
chB := make(chan int)
go func() { chB <- 0 }()
go func() { // worker goroutine
for a := range chA {
time.Sleep(time.Second * 1)
fmt.Println("A:", a)
go func(a int) { // goroutines accumulated
chB <- a // no sequence guaranteed
}(a)
}
}()
for b := range chB {
fmt.Println("B:", b)
for i := 0; i < 10; i++ {
chA <- i // sequence guaranteed
}
}
}
One-to-many with multiple worker goroutines
func main() {
chA := make(chan int)
chB := make(chan int)
go func() { chB <- 0 }()
for i := 0; i < 20; i++ {
go func() {
for a := range chA {
time.Sleep(time.Second * 1) // simulate real work
fmt.Println("A:", a)
go func(a int) { // goroutine accumulation
chB <- a
}(a)
}
}()
}
for b := range chB { // consume one
fmt.Println("B:", b)
for i := 0; i < 10; i++ { // produce many
chA <- i
}
}
}
One-to-many with counting semaphore
func main() {
worklist := make(chan []string)
go func() { worklist <- os.Args[1:] }()
seed := make(map[string]bool)
for list := range worklist { // consume one
for _, link := range list {
if !seen[link] {
seed[link] = true
go func(link string) { // goroutine accumulation
worklist <- crawl(link) // produce many
}(link)
}
}
}
}
var tokens = make(chan struct{}, 20)
func crawl(url string) []string {
tokens <- struct{}{} // acquire a token
list, err := links.Extract(url)
<-tokens // release the token
if err != nil {
log.Printf(err)
}
return list
}