new(go): More code from "Go Concurrency Patterns" video.
authorsgf <sgf.dma@gmail.com>
Wed, 1 Jun 2022 14:29:35 +0000 (17:29 +0300)
committersgf <sgf.dma@gmail.com>
Wed, 1 Jun 2022 14:29:35 +0000 (17:29 +0300)
go-concurrency-patterns/conc1.go

index 82f4a73..80373ba 100644 (file)
@@ -27,6 +27,7 @@ func main1() {
     fmt.Println("You're boring. I'm leaving.")
 }
 
+
 func main2() {
     joe := boring("Joe")
     ann := boring("Ann")
@@ -37,6 +38,7 @@ func main2() {
     fmt.Println("You're both boring. I'm leaving.")
 }
 
+
 func fanIn(input1, input2 <- chan string) <-chan string {
     c := make(chan string)
     go func() { for { c <- <-input1 } }()
@@ -44,6 +46,19 @@ func fanIn(input1, input2 <- chan string) <-chan string {
     return c
 }
 
+func fanIns(input1, input2 <- chan string) <-chan string {
+    c := make(chan string)
+    go func() {
+        for {
+            select {
+            case s := <- input1: c <- s
+            case s := <- input2: c <- s
+            }
+        }
+    }()
+    return c
+}
+
 func main3() {
     c := fanIn(boring("Joe"), boring("Ann"))
     for i := 0; i < 10; i++ {
@@ -52,8 +67,76 @@ func main3() {
     fmt.Println("You're boring. I'm leaving.")
 }
 
+
+type Message struct {
+    str string
+    wait chan bool
+}
+
+func boring4(msg string) <- chan Message {
+    c := make(chan Message)
+    // Buffering removes a block in main4() loop, when 'true' is send to
+    // 'wait' channel. Thus, next message will first arrive from the guy, who
+    // slept less. Without buffering, main4() will wait until slower guy
+    // awakes from 'Sleep' and read 'wait' channel, so the Ann will almost
+    // always be the first one.
+    waitForIt := make(chan bool, 2)
+    go func() {
+        for i := 0; ; i++ {
+            r := rand.Intn(1e3)
+            c <- Message{ fmt.Sprintf("%s %d (%d)", msg, i, r), waitForIt }
+            time.Sleep(time.Duration(r) * time.Millisecond)
+            <-waitForIt
+        }
+    }()
+    return c
+}
+
+func fanIn4(input1, input2 <- chan Message) <-chan Message {
+    c := make(chan Message)
+    go func() { for { c <- <-input1 } }()
+    go func() { for { c <- <-input2 } }()
+    return c
+}
+
+func fanIn4s(input1, input2 <- chan Message) <-chan Message {
+    c := make(chan Message)
+    go func() {
+        for {
+            select {
+            case s := <- input1: c <- s
+            case s := <- input2: c <- s
+            }
+        }
+    }()
+    return c
+}
+
+func main4() {
+    c := fanIn4s(boring4("Joe"), boring4("Ann"))
+    for i := 0; i < 5; i++ {
+        msg1 := <-c; fmt.Println(msg1.str)
+        msg2 := <-c; fmt.Println(msg2.str)
+        msg1.wait <- true
+        msg2.wait <- true
+    }
+    fmt.Println("You're boring. I'm leaving.")
+}
+
+// This is the same as main3(). 'wait' channel has no sense here, because
+// after reading a message, i immediatelly send "go on" over 'wait' channel to
+// the guy, who have spoken right now.
+func main41() {
+    c := fanIn4s(boring4("Joe"), boring4("Ann"))
+    for i := 0; i < 10; i++ {
+        msg := <-c; fmt.Println(msg.str)
+        msg.wait <- true
+    }
+    fmt.Println("You're boring. I'm leaving.")
+}
+
 func main() {
     rand.Seed(time.Now().Unix())
 
-    main3()
+    main4()
 }